Django快速入门7自定义用户模型

Django内置的用户模型允许我们立即开始与用户打交道,就像我们在前几章中刚刚对我们的Blog应用所做的那样。然而,Django官方文档强烈建议新项目使用自定义用户模型。这样想在以后对用户模型做任何改动或从一开始就使用自定义的用户模型,这就非常容易了。

所以在所有新的Django项目中总是使用自定义的用户模型。但是官方文档中的例子所演示的方法实际上并不是许多Django专家所推荐的。它使用了相当复杂的AbstractBaseUser,而如果我们只使用AbstractUser,事情就简单得多,而且还可以自定义。

因此,我们将在本章中使用AbstractUser,在这一章中,我们将正确地使用环境变量和自定义用户模型来启动新的报纸应用程序。选择报纸应用程序是为了向Django的根源致敬,它是为Lawrence Journal-World的编辑和记者建立的一个网络框架。

启动应用

$ mkdir news
$ cd news
$ django-admin startproject config .
$ python manage.py startapp accounts
$ python manage.py runserver

注意,我们没有运行migrate来配置我们的数据库,等到我们创建了新的自定义用户模型后再这样做。

config/settings.py

# config/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'accounts', # new
]
...
AUTH_USER_MODEL = 'accounts.CustomUser' # new

在config/settings.py中,我们将把accounts应用程序添加到我们的INSTALLED_APPS中。然后在文件底部使用AUTH_USER_MODEL配置来告诉Django使用我们新的自定义用户模型来代替内置的用户模型,我们将称我们的自定义用户模型为CustomUser。

accounts/models.py

from django.contrib.auth.models import AbstractUser
from django.db import models


class CustomUser(AbstractUser):
    age = models.PositiveIntegerField(null=True, blank=True)

如果你阅读关于自定义用户模型的官方文档,它建议使用AbstractBaseUser而不是AbstractUser。在我看来,这不必要地使事情复杂化,特别是对于初学者。

AbstractBaseUser需要非常精细的控制和定制水平。如果重写Django。这可能会有帮助,但如果我们只是想要用额外字段更新的自定义用户模型,更好的选择是AbstractUser,它子类化了AbstractBaseUser。换句话说,我们写的代码要少得多,把事情搞乱的机会也少。这是更好的选择,除非你真的知道你在用Django做什么!

请注意,我们的年龄字段同时使用了null和blank。这两个术语很容易混淆,但又很不同。null是与数据库有关的。当一个字段的null=True时,它可以将一个数据库条目存储为NULL,意思是没有值。blank是与验证有关的,如果blank=True,那么表单将允许空值,而如果blank=False,则需要值。在实践中,null和 blank通常以这种方式一起使用,因此表单允许空值,而数据库将该值存储为NULL。

需要注意的常见问题是,字段类型决定了如何使用这些值。只要你有基于字符串的字段,如CharField或TextField,像我们所做的那样设置null和blank将导致数据库中出现两个可能的 "无数据 "值。这是个坏主意。Django的惯例是使用空字符串'',而不是NULL。

表单

我们与新的CustomUser模型的交互方式有哪些?一种情况是当用户在我们的网站上注册新的账户。另一种是在管理应用程序中,允许我们作为超级用户修改现有用户。所以我们需要为这个功能更新两个内置表单。UserCreationForm和UserChangeForm。

accounts/forms.py

# accounts/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser


class CustomUserCreationForm(UserCreationForm):

    class Meta(UserCreationForm):
        model = CustomUser
        fields = UserCreationForm.Meta.fields + ('age',)


class CustomUserChangeForm(UserChangeForm):

    class Meta:
        model = CustomUser
        fields = UserChangeForm.Meta.fields

对于这两个新表单,我们使用Meta类来覆盖默认字段,将模型设置为我们的CustomUser,并通过包括所有默认字段的Meta.field使用默认字段。要添加我们的自定义年龄字段,我们只需将它放在最后,它将自动显示在我们未来的注册页面上。

CustomUser模型包含默认用户模型的所有字段和我们设置的额外的年龄字段。这些默认字段是什么呢?原来有很多,包括用户名、名、姓、电子邮件、密码、组等等。然而,当用户在Django上注册新账户时,默认表单只要求输入用户名、电子邮件和密码。这告诉我们,UserCreationForm的默认字段设置只是用户名、电子邮件和密码,尽管还有很多字段可用。

这对你来说可能并不容易,因为正确理解表单和模型需要一些时间。在下一章中,我们将创建我们自己的注册、登录和注销页面,这将使我们的CustomUser模型和表单更清晰地联系在一起。所以,请抓紧时间!

accounts/admin.py

# accounts/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser


class CustomUserAdmin(UserAdmin):
    add_form = CustomUserCreationForm
    form = CustomUserChangeForm
    model = CustomUser


admin.site.register(CustomUser, CustomUserAdmin)

进行数据迁移和创建超级用户:

$ python manage.py makemigrations accounts
$ python manage.py migrate
$ python manage.py createsuperuser

accounts/admin.py

# accounts/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin

from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser


class CustomUserAdmin(UserAdmin):
    add_form = CustomUserCreationForm
    form = CustomUserChangeForm
    model = CustomUser
    list_display = ['email', 'username', 'age', 'is_staff', ] # new
    fieldsets = UserAdmin.fieldsets + ( # new
        (None, {'fields': ('age',)}),
    )
    add_fieldsets = UserAdmin.add_fieldsets + ( # new
        (None, {'fields': ('age',)}),
    )


admin.site.register(CustomUser, CustomUserAdmin)

小结

随着我们的自定义用户模型的完成,我们现在可以专注于构建我们报纸网站的其他部分。在下一章,我们将配置和定制注册、登录和注销页面。

推荐阅读更多精彩内容