from django.db import models from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin from django.utils import timezone from django.utils.translation import gettext_lazy as _ class CustomUserManager(BaseUserManager): """ 自定义用户模型的管理器。 """ def create_user(self, email, phone_number, password=None, **extra_fields): """ 创建并保存一个具有给定邮箱、手机号和密码的用户。 """ print(f"--- CustomUserManager: create_user called ---") print(f"Received - Email: {email}, Phone: {phone_number}, Password provided: {'Yes' if password else 'No'}") print(f"Received - Extra fields: {extra_fields}") if not email: print("Validation Error in create_user: Email is required") raise ValueError(_('用户必须有一个邮箱地址')) if not phone_number: print("Validation Error in create_user: Phone number is required") raise ValueError(_('用户必须有一个手机号')) email = self.normalize_email(email) extra_fields.setdefault('is_staff', False) extra_fields.setdefault('is_superuser', False) # is_active 字段在Admin表单中是可编辑的,所以extra_fields中可能已经有它的值 # 如果extra_fields中没有is_active,我们再设置默认值 if 'is_active' not in extra_fields: extra_fields.setdefault('is_active', True) print(f"Normalized email: {email}") print(f"Fields for model instance before creation: email={email}, phone_number={phone_number}, extra_fields={extra_fields}") user = self.model(email=email, phone_number=phone_number, **extra_fields) if password: user.set_password(password) print("Password has been set.") else: # 对于Admin创建,UserCreationForm应该总是提供密码。 # 如果通过其他方式调用create_user且没有密码,这里可以记录一个警告或抛出错误。 print("WARNING in create_user: Password was not provided. User will not be able to log in with a password.") try: user.save(using=self._db) print(f"--- User saved successfully with ID: {user.id} ---") except Exception as e: print(f"--- ERROR during user.save() in create_user: {e} ---") raise # 重新抛出异常,以便Django能捕获 return user def create_superuser(self, email, phone_number, password=None, **extra_fields): """ 创建并保存一个具有给定邮箱、手机号和密码的超级用户。 """ print(f"--- CustomUserManager: create_superuser called ---") print(f"Received - Email: {email}, Phone: {phone_number}, Password provided: {'Yes' if password else 'No'}") print(f"Received - Extra fields for superuser: {extra_fields}") # create_superuser 应该确保 is_staff 和 is_superuser 为 True extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) extra_fields.setdefault('is_active', True) # 超级用户默认激活 if extra_fields.get('is_staff') is not True: print("Error in create_superuser: is_staff must be True.") raise ValueError(_('超级用户必须将 is_staff 设置为 True.')) if extra_fields.get('is_superuser') is not True: print("Error in create_superuser: is_superuser must be True.") raise ValueError(_('超级用户必须将 is_superuser 设置为 True.')) # 调用 create_user 来完成创建,这样可以复用验证和密码设置逻辑 # create_user 内部已经有了打印语句 # 注意:create_user 会将 is_staff 和 is_superuser 设为 False(如果它们不在extra_fields中) # 所以我们需要在调用 create_user 后,再把它们强制设为 True。 # 或者,修改create_user,如果is_staff/is_superuser在extra_fields中提供了,就不覆盖。 # 当前的create_user是 extra_fields.setdefault,所以如果extra_fields已经有is_staff=True,它不会被覆盖。 # 我们直接调用 create_user,它会处理大部分逻辑 # 然后确保 is_staff 和 is_superuser 属性是 True (虽然 setdefault 应该已经处理了) print(f"Calling create_user from create_superuser with fields: email={email}, phone_number={phone_number}, extra_fields={extra_fields}") user = self.create_user(email, phone_number, password, **extra_fields) # 再次确保超级用户权限 (理论上 setdefault 已经处理,但双重保险) # if not user.is_staff or not user.is_superuser: # user.is_staff = True # user.is_superuser = True # try: # user.save(using=self._db) # print(f"--- Superuser (ID: {user.id}) permissions (is_staff, is_superuser) re-saved ---") # except Exception as e: # print(f"--- ERROR during superuser permission re-save: {e} ---") # raise return user class InterestTag(models.Model): name = models.CharField( _('标签名称'), max_length=50, unique=True, help_text=_('兴趣标签的名称,例如:摄影、篮球、Python编程') ) created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('创建时间')) class Meta: verbose_name = _('兴趣标签') verbose_name_plural = _('兴趣标签们') ordering = ['name'] def __str__(self): return self.name class CustomUser(AbstractBaseUser, PermissionsMixin): email = models.EmailField(_('邮箱地址'), unique=True) phone_number = models.CharField(_('手机号'), max_length=20, unique=True) nickname = models.CharField(_('昵称'), max_length=100, blank=True) avatar = models.ImageField(_('头像'), upload_to='avatars/', null=True, blank=True) bio = models.TextField(_('简介'), blank=True) school = models.CharField(_('学校'), max_length=100, blank=True) is_staff = models.BooleanField( _('职员状态'), default=False, help_text=_('指明用户是否可以登录到管理站点。'), ) is_active = models.BooleanField( _('激活状态'), default=True, # 默认用户是激活的 help_text=_( '指明用户是否被认为是活跃的。' '取消选择此项而不是删除账户。' ), ) date_joined = models.DateTimeField(_('注册日期'), default=timezone.now) interests = models.ManyToManyField( 'InterestTag', verbose_name=_('兴趣标签'), blank=True, related_name='users_with_interest' ) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['phone_number', 'nickname'] objects = CustomUserManager() @property def display_name(self): return self.nickname if self.nickname else self.email def __str__(self): return self.email class Meta: verbose_name = _('用户') verbose_name_plural = _('用户们') # 如果有自定义的 save 方法,确保它调用了 super().save() # def save(self, *args, **kwargs): # print("--- CustomUser save() called ---") # # some custom logic # super().save(*args, **kwargs) # 确保调用父类的save # print("--- CustomUser save() finished ---")