首页电脑使用django 自定义cookie django 自定义user

django 自定义cookie django 自定义user

圆圆2025-07-12 22:01:33次浏览条评论

Django自定义User模型与Mypy类型检查:解决字段重定义不兼容错误 论文讨论在 Django 项目中进行,当用户模型继承自 AbstractUser 并尝试重新定义内置字段(如电子邮件)时,mypy 类型检查器报告的“不兼容”文章详细分析了错误产生的原因,并提供了一种根本性的解决方案:将自定义用户模型从继承Abstract改为用户继承AbstractBaseUser和PermissionsMixin。此方法提供了更大的灵活性,允许完全控制用户模型的定义字段,从而消除mypy的类型冲突,同时保留Django的认证和权限系统功能。 问题背景:Django自定义用户模型与Mypy类型冲突

在django项目中,为了满足特定的业务需求,通常会自定义用户模型。最常见的方式是继承django内置的abstractuser类。abstractuser提供了一个功能强大的用户模型,包含了如用户名、密码、电子邮件、姓名、激活状然而,当开发者需要对抽象用户中已定义的某个字段进行修改(例如,改变电子邮件字段的null、空白或唯一属性,这样的索引行为)时,可能会遇到类型检查工具mypy报错。

例如,以下代码尝试重新定义电子邮件字段:from django.contrib.auth.models import AbstractUserfrom django.db import modelsclass User(AbstractUser): # ... 其他字段或方法 ... email = models.EmailField(db_index=True, Blank=True, null=True, unique=True) # ...登录后复制

当运行mypy进行类型检查时,可能会收到如下错误信息:error: Incompromise types in assignment (expression has type quot;EmailField[str | int | Combinable | None, str | None]quot;,基类 quot;AbstractUserquot;定义类型为 quot;EmailField[str | int | Combinable, str]quot;) [赋值]登录后复制

这个错误表明,在User类中对email字段的重新赋值,类型与父类AbstractUser中email字段的定义不兼容。mypy认为AbstractUser已经为email字段设置了严格的类型(例如,不允许None值),而自定义的定义(例如,null=True)引入了None的可能性,从而导致类型不匹配。简单地使用其#类型:忽略忽略这个错误会导致列出层次的问题,因为mypy将无法确定电子邮件字段的类型,从而在整个代码库中引发大量的无法确定“电子邮件”类型错误,失去了类型检查的意义。

2.解决方案:转向AbstractBaseUser

解决此类型不兼容问题的根本方法是改变自定义User模型的继承基类。AbstractUser是AbstractBaseUser的一个具体实现,它在AbstractBaseUser的基础上添加了许多常用的字段。AbstractBaseUser封装了一个更简单的抽象类,它只提供了用户认证所需的核心功能(如密码散列和会话管理),但不包含任何具体的用户信息字段(如用户名、电子邮件、姓名、权限等)。

通过继承AbstractBaseUser,开发者可以完全自由地定义用户模型的所有字段,包括那些在AbstractUser中预定义的字段。为了保留AbstractUser提供的权限系统功能(如is_staff, is_superuser, groups, user_permissions),还需要同时继承PermissionsMixin。

以下是修改后的自定义User模型示例:from django.contrib.auth.models import AbstractBaseUser, PermissionsMixinfrom django.db import modelsfrom django.utils.translation import gettext_lazy as _class User(AbstractBaseUser, PermissionsMixin): # 必须定义一个字段作为 USERNAME_FIELD,例如 email email = models.EmailField(_('email address'), db_index=True, Blank=True, null=True, unique=True) # 必须定义一个字段作为唯一标识符,通常是 email 或 username USERNAME_FIELD = 'email' # 必须定义在创建超级用户时需要输入的字段列表 REQUIRED_FIELDS = [] # 如果 email 是唯一标识符且允许为 None,则不需要其他必填字段 # 添加 AbstractUser中常见的字段,以保持功能界限first_name = models.CharField(_('first name'),max_length=150,blank=True) last_name = models.CharField(_('姓氏'), max_length=150, blank=True) is_staff = models.BooleanField( _('员工状态'), default=False, help_text=_('指定用户是否可以登录此管理站点。'), ) is_active = models.BooleanField( _('活跃'), default=True, help_text=_( '指定此用户是否应被视为活跃用户。 ' '取消选择此项而不是删除帐户。' ), ) date_joined = models.DateTimeField(_('加入日期'), auto_now_add=True) objects = UserManager() # 需要自定义一个 UserManager 来处理用户创建 class Meta: verbose_name = _('用户') verbose_name_plural = _('用户') def clean(self): super().clean() se

lf.email = self.__class__.objects.normalize_email(self.email) def get_full_name(self): quot;quot;quot; 返回 first_name 加上 last_name,中间有一个空格。 quot;quot;quot; full_name = 's' (self.first_name, self.last_name) return full_name.strip() def get_short_name(self): quot;quot;quot;返回用户的简称。quot;quot;quot; return self.first_name def email_user(self, subject, message, from_email=None, **kwargs): quot;quot;quot;发送电子邮件至此user.quot;quot;quot;send_mail(subject, message, from_email, [self.email], **kwargs)登录后复制

重要注意事项:

USERNAME_FIELD:当使用AbstractBaseUser时,你必须在自定义用户模型中指定一个唯一的字段作为USERNAME_FIELD。这通常是email或一个自定义的用户名字段。

REQUIRED_FIELDS: 还定义了REQUIRED_FIELDS列表,它包含了在通过createsuperuser命令创建用户时,除了USERNAME_FIELD和密码之外,必须提供的字段。

自定义UserManager:抽象你的BaseUser不提供默认的对象管理器来处理需要用户创建的情况。你需要创建一个自定义的UserManager,需要实现create_user和create_superuser方法。

例如:from django.contrib.auth.models import BaseUserManagerclass UserManager(BaseUserManager): def create_user(self, email, password=None, **extra_fields): if not email: raise ValueError('必须设置 Email 字段') email = self.normalize_email(email) user = self.model(email=email, **extra_fields) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, email, password=None, **extra_fields): 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: raise ValueError('超级用户必须 is_staff=True.') if extra_fields.get('is_superuser') is not True: raise ValueError('Superuser must have is_superuser=True.') return self.create_user(email,password, **extra_fields)登录后复制

然后蜡烛管理器赋予用户模型的objects属性:objects = UserManager()。 3. 优势与考量

优势:完全的字段控制:继承AbstractBaseUser提供了对用户模型字段的完全控制,避免了与父类预定义字段的类型冲突,尤其是在使用mypy解决等严格类型检查工具时。更响亮的职责分离:AbstractBaseUser集中于认证核心逻辑,而PermissionsMixin处理权限,使模型结构更清晰。Mypy错误:这是mypy在定义的重AbstractUser字段时报告的不兼容类型错误的最直接和推荐的方法。

考量:更多的样板代码:首先于AbstractUser,使用AbstractBaseUser意味着你需要手动定义所有常用字段(如first_name,last_name,is_staff,is_active,date_joined等),并实现自定义的UserManager。

这增加了初始设置的复杂性。迁移影响:如果项目上线且使用了继承AbstractUser的自定义模型,切换到AbstractBaseUser可能需要进行数据迁移,确保现有用户数据能够正确映射到新的模型结构。必须在生产环境部署前进行充分的测试。4. 总结

当Django项目与mypy集成时,重新定义AbstractUser中默认字段的类型冲突是一个常见问题。通过将自定义User模型从继承AbstractUser改为继承AbstractBaseUser和PermissionsMixin,开发者可以对用户模型字段的完全控制,从而彻底解决mypy的类型不兼容的错误。尽管这会引入一些额外的样板代码,但从长远来看看来,它提供了更大的灵活性和更严格的类型安全性,是构建健壮Django应用的重要实践。一定记得,在切换基类时,正确实现USERNAME_FIELD、REQUIRED_FIELDS以及自定义UserManager至关重要。

以上就是Django用户模型与Mypy类型检查:解决字段重定义不兼容错误的详细内容,更多请关注乐哥常识网其他相关文章!

Django自定义U
ChromeDriver怎么读 chromedriver参数
相关内容
发表评论

游客 回复需填写必要信息