""" 用户模块模型 """ from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin from django.db import models class UserManager(BaseUserManager): """用户管理器""" def create_user(self, phone, password=None, **extra_fields): if not phone: raise ValueError('手机号不能为空') user = self.model(phone=phone, **extra_fields) if password: user.set_password(password) user.save(using=self._db) return user def create_superuser(self, phone, password=None, **extra_fields): extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) return self.create_user(phone, password, **extra_fields) class User(AbstractBaseUser, PermissionsMixin): """用户模型""" id = models.BigAutoField(primary_key=True) phone = models.CharField('手机号', max_length=20, unique=True) nickname = models.CharField('昵称', max_length=50, blank=True, default='') avatar = models.URLField('头像', max_length=500, blank=True, default='') gender = models.CharField( '性别', max_length=10, choices=[('male', '男'), ('female', '女'), ('unknown', '未知')], default='unknown' ) birthday = models.DateField('生日', null=True, blank=True) points = models.IntegerField('积分余额', default=0) is_active = models.BooleanField('是否激活', default=True) is_staff = models.BooleanField('是否管理员', default=False) is_pending_deletion = models.BooleanField('是否待注销', default=False) deletion_requested_at = models.DateTimeField('注销申请时间', null=True, blank=True) created_at = models.DateTimeField('创建时间', auto_now_add=True) updated_at = models.DateTimeField('更新时间', auto_now=True) objects = UserManager() USERNAME_FIELD = 'phone' REQUIRED_FIELDS = [] class Meta: db_table = 'user' verbose_name = '用户' verbose_name_plural = '用户' def __str__(self): return self.phone class PointsRecord(models.Model): """积分流水记录""" TYPE_CHOICES = [ ('unlock_shelf', '解锁书架'), ('reward', '奖励'), ('admin_adjust', '管理员调整'), ('generate_music', '生成音乐'), ('refund_music', '音乐生成退款'), ] user = models.ForeignKey( User, on_delete=models.CASCADE, related_name='points_records', verbose_name='用户' ) amount = models.IntegerField('变动数量') type = models.CharField('类型', max_length=30, choices=TYPE_CHOICES) description = models.CharField('描述', max_length=200, blank=True, default='') created_at = models.DateTimeField('创建时间', auto_now_add=True) class Meta: db_table = 'points_record' verbose_name = '积分流水' verbose_name_plural = verbose_name ordering = ['-created_at'] indexes = [ models.Index(fields=['user', '-created_at']), ] def __str__(self): return f'{self.user.phone} {self.amount:+d} ({self.type})' class SmsCode(models.Model): """短信验证码""" phone = models.CharField('手机号', max_length=20) code = models.CharField('验证码', max_length=6) is_used = models.BooleanField('是否已使用', default=False) expire_at = models.DateTimeField('过期时间') created_at = models.DateTimeField('创建时间', auto_now_add=True) class Meta: db_table = 'sms_code' verbose_name = '短信验证码' verbose_name_plural = verbose_name indexes = [ models.Index(fields=['phone', 'code']), models.Index(fields=['expire_at']), ] def __str__(self): return f"{self.phone} - {self.code}"