关于自定义用户模型的 Django 最佳实践

Posted

技术标签:

【中文标题】关于自定义用户模型的 Django 最佳实践【英文标题】:Django best practices regarding custom User models 【发布时间】:2021-10-20 07:57:45 【问题描述】:

这更像是一个一般性的最佳实践问题。在 Django 中启动新项目时,一般是创建自定义的 User 模型,还是依赖默认的?

如果我不弄乱默认的用户模型,我个人觉得它看起来更干净。如果我想添加任何其他属性,我觉得添加与用户具有一对一/外键关系的ProfileUserInfo 模型会更简单。

我读过很多关于 Django 的文章,但是不同意这一点。显然建议构建自定义用户模型?我很好奇每个人都在做什么,以及如果我做出这些选择中的任何一个,我到底错过了什么。

【问题讨论】:

从需要额外字段的那一刻起,实现自定义用户模型通常会更干净。只要您对默认的User 模型存储的用户数据感到满意,使用User 模型会更好。虽然您可以使用 Profile 模型,但它通常会导致更多查询,并且您需要实现自动创建/更新配置文件的逻辑,这通常不是那么优雅。 使用Profile 因此是否应该使用信号等不是一个好主意,因为这些信号等通常包含使发生的事情不太清楚的逻辑,此外还有一些方法规避这些信号,从而降低可靠性。 @WillemVanOnsem 是的,你是对的,写所有更新Profile的信号有点麻烦,谢谢你的回答! 【参考方案1】:

当您必须向用户模型添加新字段或逻辑(例如使用电子邮件而不是用户名登录或添加新权限)时,自定义用户模型是一种很好的做法。 如果您的应用程序很简单并且您不必添加新字段,则可以使用默认用户模型。 其他解决方案是保持用户模型完整并创建一个与用户具有 OneToOne 关系的“用户配置文件”模型,但您必须手动创建配置文件并将其添加到用户,或者可能使用 django 信号来创建用户配置文件每次创建新用户时。 我个人不推荐最后一个解决方案。 因此,如果您必须添加新字段或逻辑,则应创建自定义用户模型,否则请坚持使用默认用户模型。 如果您使用自定义模型,请记住将新字段添加到管理站点 这是一个例子

    class User(AbstractUser):
        worker = models.OneToOneField(WorkerModel, on_delete=models.CASCADE, 
                    related_name="user", verbose_name=_("Trabajador"), null=True, blank=True)
    
        job = models.CharField(verbose_name="Cargo",max_length=50, null=True, blank=True)
        department = models.CharField(verbose_name="Departamento",max_length=50, null=True, blank=True)
        avatar = models.ImageField(verbose_name="Imagen", upload_to="user_avatar",
                                                    null=True, blank=True)
        class Meta:
            default_permissions = ()
            verbose_name="Usuario"
            verbose_name_plural="Usuarios"
            permissions = (
                ("secretario", "Secretario(a)"),
                ("director", "Director"),
            
            )

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User #, UserProfileModel
from django.utils.translation import gettext, gettext_lazy as _

class UserAdminInherited(UserAdmin):
    autocomplete_fields = ['worker']
    fieldsets = (
        (None, 'fields': ('username', 'password')),
        (_('Personal info'), 'fields': ('first_name', 'last_name', 'email','job','department','avatar')),
        (_('Worker info'), 'fields': ('worker',)),
        (_('Permissions'), 
            'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions'),
        ),
        (_('Important dates'), 'fields': ('last_login', 'date_joined')),
    )

admin.site.register(User, UserAdminInherited)

【讨论】:

有道理,感谢详细解答! 我很乐意提供帮助

以上是关于关于自定义用户模型的 Django 最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

django 在模型自定义保存中访问上传的文件,最佳实践?

Django - 异常处理最佳实践和发送自定义错误消息 [关闭]

django 设计模式/最佳实践:过滤查询集

从显示自定义字段的 Django 模型呈现可排序表的最佳方法?

最佳实践是使用模型还是简单属性?

Django在多个项目之间共享相同用户模型和数据库的最佳方式