在 Django 用户模型中需要 first_name 和 last_name

Posted

技术标签:

【中文标题】在 Django 用户模型中需要 first_name 和 last_name【英文标题】:Requiring first_name and last_name in Django User model 【发布时间】:2017-10-12 10:42:56 【问题描述】:

django.contrib.auth.models.User 中,first_namelast_name 字段都有 blank=True。如何在我自己的模型中制作blank=False, null=False

这里是我的实现,基本按照Extending the existing User model的说明:

models.py

class Fellow(models.Model):

    user = models.OneToOneField(
        User,
        on_delete=models.CASCADE
    )

    first_name = models.CharField(
        _("first_name"),
        max_length=30,
    )
    last_name = models.CharField(
        _("last_name"),
        max_length=30,
    )

    # other fields omitted

from . import signals

信号.py

from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

from .models import Fellow


@receiver(post_save, sender=User)
def create_fellow_on_user_create(sender, instance, created, **kwargs):
    if created:
        Fellow.objects.create(user=instance)

但是,我在python manage.py shell 中测试时出错:

>>> f = Fellow.objects.create(username='username', password='passwd')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/db/models/query.py", line 392, in create
    obj = self.model(**kwargs)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/db/models/base.py", line 571, in __init__
    raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0])
TypeError: 'username' is an invalid keyword argument for this function

【问题讨论】:

您应该从原始 User 类派生模型。 @KlausD。你的意思是直接继承User?但是文档中的示例代码写的是class Employee(models.Model):而不是class Employee(User): ... @KlausD。这样做会给我一个错误:django.core.exceptions.FieldError: Local field 'first_name' in class 'Fellow' ***es with field of the same name from base class 'User'. 【参考方案1】:

您误解了本教程。您所指的员工示例解释了如何添加到User,这是通过OneToOneField 完成的,它使原始User 模型保持不变,但出于所有实际目的,就好像User 有一个新的名为department 的字段。这是通过在数据库中创建两个单独的表来实现的。

有一个警告,在EmployeeFellow 中,如果不先创建User 实例,您将无法按照您尝试过的方式直接创建新实例。那是因为这些模型都没有直接拥有用户名字段。所以分两步完成

user = User(username='Sun')   
user.set_password('123')
user.save()

f = Fellow(user=user)

但这种方法仍然不太理想。您在两个模型中都有一个 first_name 和 last_name 字段。它总是会导致混乱。正确的方法是继承 AbstractBaseUser

class Fellow(AbstractBaseUser):

   first_name = models.CharField(max_length=254)

AbstractBaseUser 是一个简单的用户(参见代码:https://github.com/django/django/blob/master/django/contrib/auth/base_user.py#L47),它没有名字和姓氏,因此您可以根据需要添加它们。

【讨论】:

【参考方案2】:

您所指的文档的第一行说

有两种方法可以扩展默认的 User 模型而不用替换你自己的模型

关键字是没有替换

我在这里看到 3 个选项:

1) 从AbstractBaseUser 派生用户类并定义所有必填字段。您可以以AbstractUser 为例。

2) 向 UserSerializer 或用户保存模型上的 pre_save 信号添加验证,并验证 first_namelast_name 字段。最简单的方法,但不是长期项目的好选择。

3) 按照您选择的方式添加对User 模型的引用作为user。定义first_namelast_name,但确保Fellow.first_nameFellow.user.first_name 之间的这些字段没有重复。这可能很难,因为其他开发人员可能会误解这个想法。 由于尚未创建用户模型并且启动Fellow 实例的正确方法是:

user = User.objects.create(username='test', email='test@example.com')
fellow = Fellow.objects.create(user=user, first_name='firstname', last_name='last_name')

【讨论】:

以上是关于在 Django 用户模型中需要 first_name 和 last_name的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 用户模型中需要 first_name 和 last_name

在 Django 中使用更多字段扩展用户模型的最佳方法是啥?

何时在 Django 1.5 中使用自定义用户模型

在 Django 用户模型中独一无二

从自定义 Django 用户模型中删除密码

在 Django 中使用自定义用户模型总是在模板中返回匿名用户