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)

小结

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容