在Django用户模型中要求输入名字和姓氏

4
django.contrib.auth.models.User 中,first_namelast_name 字段都有 blank=True。我怎样才能在自己的模型中使它们变为 blank=False, null=False
这是我的实现,基本上遵循了 扩展现有用户模型 的说明:

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

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类派生你的模型。 - Klaus D.
@KlausD. 你的意思是直接从 User 派生子类吗?但是文档中的示例代码写的是 class Employee(models.Model): 而不是 class Employee(User):... - nalzok
@KlausD. 这样做会导致错误:django.core.exceptions.FieldError: Fellow 类中的本地字段 'first_name' 与基类 'User' 中同名的字段冲突。 - nalzok
2个回答

1
你误解了教程。你所提到的员工示例是解释如何添加到User中,这是通过使用OneToOneField完成的,这使得原始的User模型保持不变,但实际上就像User有一个名为department的新字段一样。这是通过在数据库中创建两个单独的表来实现的。
有一个注意点,在EmployeeFellow中,您不能直接按照您尝试的方式创建新实例,而是必须先创建User实例。这是因为这些模型都没有直接拥有用户名字段。因此,请分两步操作。
user = User(username='Sun')   
user.set_password('123')
user.save()

f = Fellow(user=user)

但这种方法还不够理想。在两个模型中都有名字和姓氏字段,这总会导致混淆。正确的方法是子类化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),它不包含 first_name 和 last_name 属性,因此您可以根据需要添加它们。


0

你所查看的文档的第一行说:

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

关键字是不替换

我在这里看到3个选项:

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

2)将验证添加到UserSerializer或pre_save 信号上以验证用户保存模型中的first_name last_name 字段。最简单的方法,但不适合长期项目。

3) 通过将 User 模型作为 user 的引用来选择你选择的方式。定义 first_namelast_name,但确保在 Fellow.first_nameFellow.user.first_name 之间没有这些字段的重复。这可能很困难,因为其他开发人员可能会误解这个想法。
你遇到的错误是因为尚未创建 User 模型,初始化 Fellow 实例的正确方法是:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接