原文:https://www.cnblogs.com/linxiyue/p/4061044.html
扩展已有的用户模型Extending the existing User model
有两种方法来扩展默认的User Model而不用重写自己的模型。如果你不需要改变存储在数据库中的字段,而只是需要改变Model的行为,您可以创建一个基于User的代理Model。允许的行为包括默认的ordering,custom managers, 或者 custom model methods。
如果你想存储与User有关的信息,可以使用一个OneToOneField字段关联到一个存储额外信息的Model。这一Model通常被称为一个profile model模型,它可以用来存储一些非验证所需的信息。例如,你可以创建一个Model:
1
2
3
4
5
|
from
django.contrib.auth.models
import
User
class
Employee(models.Model):
user
=
models.OneToOneField(User)
department
=
models.CharField(max_length
=
100
)
|
访问:
1
2
|
>>> u
=
User.objects.get(username
=
'fsmith'
)
>>> freds_department
=
u.employee.department
|
如果需要将profile model的字段添加到admin管理界面的user页面上,需要在应用app的admin.py中定义InlineModelAdmin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
from
django.contrib
import
admin
from
django.contrib.auth.admin
import
UserAdmin
from
django.contrib.auth.models
import
User
from
my_user_profile_app.models
import
Employee
# Define an inline admin descriptor for Employee model
# which acts a bit like a singleton
class
EmployeeInline(admin.StackedInline):
model
=
Employee
can_delete
=
False
verbose_name_plural
=
'employee'
# Define a new User admin
class
UserAdmin(UserAdmin):
inlines
=
(EmployeeInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
|
这些profile models并不特别,只是与User Model有一个OneToOne链接。所以当一个user实例创建时,profile model并不会自动创建。
重写User模型Substituting a custom User model
有时候User Model并不适合你的网站,比如你要将email而不是username作为认证标识,这时候就需要重写User Model。
首先,需要将settings中的默认User Model覆盖:
1
|
AUTH_USER_MODEL
=
'myapp.MyUser'
|
引用Referencing the User model
如果AUTH_USER_MODEL已被重设,那当User Model通过ForeignKey或者ManyToManyField访问时,不能直接访问,而是要通过AUTH_USER_MODEL来访问:
1
2
3
4
5
|
from
django.conf
import
settings
from
django.db
import
models
class
Article(models.Model):
author
=
models.ForeignKey(settings.AUTH_USER_MODEL)
|
指定Specifying a custom User model
最简单的定制一个User Model的方法是继承用户类AbstractBaseUser。
源码:
一些关键的字段和方法:
USERNAME_FIELD
必需的。设置认证标识。设置成标识的字段unique必须为True。
1
2
3
4
|
class
MyUser(AbstractBaseUser):
identifier
=
models.CharField(max_length
=
40
, unique
=
True
)
...
USERNAME_FIELD
=
'identifier'
|
上面的例子中identifier即作为MyUser的认证标识。
REQUIRED_FIELDS
字段name组成的列表。当创建superuser时用到的字段。
1
2
3
4
5
6
|
class
MyUser(AbstractBaseUser):
...
date_of_birth
=
models.DateField()
height
=
models.FloatField()
...
REQUIRED_FIELDS
=
[
'date_of_birth'
,
'height'
]
|
列表中不应该包含USERNAME_FIELD字段和password字段。
is_active
AbstractBaseUser默认为True。
get_full_name()
get_short_name()
AbstractBaseUser的子类必须定义的两个方法。
下面为一些AbstractBaseUser的子类可以使用的方法:
get_username()
返回USERNAME_FIELD的值.
is_anonymous()
返回False。
is_authenticated()
返回True。检查一个user是否已登录。
set_password(raw_password)
设置密码
check_password(raw_password)
检查密码是否正确
set_unusable_password()
设置user无密码
has_usable_password()
Returns False if set_unusable_password() has been called for this user.
get_session_auth_hash()
返回密码字段的HMAC. Used for Session invalidation on password change.
还需要为自己的User Model定义一个custom manager。
class models.CustomUserManager
create_user(*username_field*, password=None, **other_fields)
接受username field和required字段来创建用户。例如,如果使用email作为username field, date_of_birth作为required field:
1
2
3
|
def
create_user(
self
, email, date_of_birth, password
=
None
):
# create user here
...
|
create_superuser(*username_field*, password, **other_fields)
创建superuser
1
2
3
|
def
create_superuser(
self
, email, date_of_birth, password):
# create superuser here
...
|
create_superuser中的password是必需的。
扩展内置的表单Custom users and the built-in auth forms
UserCreationForm
依赖于User Model. 扩展User时必须重写。
UserChangeForm
依赖于User Model. 扩展User时必须重写。
AuthenticationForm
Works with任何AbstractBaseUser子类 ,and will adapt to use the field defined in USERNAME_FIELD.
PasswordResetForm
Assumes that the user model has an integer primary key, has a field named email that can be used to identify the user, and a boolean field named is_active to prevent password resets for inactive users.
SetPasswordForm
Works with 任何AbstractBaseUser子类
PasswordChangeForm
Works with任何AbstractBaseUser子类
AdminPasswordChangeForm
Works with任何AbstractBaseUser子类。
定制admin功能Custom users and Admin
如果想自己定义的User Model能与admin管理系统一起使用,还需要定义一些字段和方法。
is_staff
是否允许user访问admin界面
is_active
用户是否活跃。
has_perm(perm, obj=None):
user是否拥有perm权限。
has_module_perms(app_label):
user是否拥有app中的权限
定制用户和权限Custom users and permissions
如果要定制User的权限系统,最简单的方法是继承PermissionsMixin
源码:
Django内置的User对象就继承了AbstractBaseUser和PermissionsMixin。
源码:
现在可以看一个完整的自定义User Model例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
from
django.db
import
models
from
django.contrib.auth.models
import
(
BaseUserManager, AbstractBaseUser
)
class
MyUserManager(BaseUserManager):
def
create_user(
self
, email, date_of_birth, password
=
None
):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
if
not
email:
raise
ValueError(
'Users must have an email address'
)
user
=
self
.model(
email
=
self
.normalize_email(email),
date_of_birth
=
date_of_birth,
)
user.set_password(password)
user.save(using
=
self
._db)
return
user
def
create_superuser(
self
, email, date_of_birth, password):
"""
Creates and saves a superuser with the given email, date of
birth and password.
"""
user
=
self
.create_user(email,
password
=
password,
date_of_birth
=
date_of_birth
)
user.is_admin
=
True
user.save(using
=
self
._db)
return
user
class
MyUser(AbstractBaseUser):
email
=
models.EmailField(
verbose_name
=
'email address'
,
max_length
=
255
,
unique
=
True
,
)
date_of_birth
=
models.DateField()
is_active
=
models.BooleanField(default
=
True
)
is_admin
=
models.BooleanField(default
=
False
)
objects
=
MyUserManager()
USERNAME_FIELD
=
'email'
REQUIRED_FIELDS
=
[
'date_of_birth'
]
def
get_full_name(
self
):
# The user is identified by their email address
return
self
.email
def
get_short_name(
self
):
# The user is identified by their email address
return
self
.email
def
__str__(
self
):
# __unicode__ on Python 2
return
self
.email
def
has_perm(
self
, perm, obj
=
None
):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return
True
def
has_module_perms(
self
, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return
True
@property
def
is_staff(
self
):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return
self
.is_admin
|
可以看到manager定义了create_user()和create_superuser()方法,MyUser定义了USERNAME_FIELD,REQUIRED_FIELDS字段和get_full_name(),get_short_name()方法,为了能与admin一起使用,还定义了is_active,is_staff,has_perm(),has_module_perms()
要在admin中注册自定义的MyUser,还需要在app的admin.py中重写UserCreationForm和UserChangeForm:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
from
django
import
forms
from
django.contrib
import
admin
from
django.contrib.auth.models
import
Group
from
django.contrib.auth.admin
import
UserAdmin
from
django.contrib.auth.forms
import
ReadOnlyPasswordHashField
from
customauth.models
import
MyUser
class
UserCreationForm(forms.ModelForm):
"""A form for creating new users. Includes all the required
fields, plus a repeated password."""
password1
=
forms.CharField(label
=
'Password'
, widget
=
forms.PasswordInput)
password2
=
forms.CharField(label
=
'Password confirmation'
, widget
=
forms.PasswordInput)
class
Meta:
model
=
MyUser
fields
=
(
'email'
,
'date_of_birth'
)
def
clean_password2(
self
):
# Check that the two password entries match
password1
=
self
.cleaned_data.get(
"password1"
)
password2
=
self
.cleaned_data.get(
"password2"
)
if
password1
and
password2
and
password1 !
=
password2:
raise
forms.ValidationError(
"Passwords don't match"
)
return
password2
def
save(
self
, commit
=
True
):
# Save the provided password in hashed format
user
=
super
(UserCreationForm,
self
).save(commit
=
False
)
user.set_password(
self
.cleaned_data[
"password1"
])
if
commit:
user.save()
return
user
class
UserChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password
=
ReadOnlyPasswordHashField()
class
Meta:
model
=
MyUser
fields
=
(
'email'
,
'password'
,
'date_of_birth'
,
'is_active'
,
'is_admin'
)
def
clean_password(
self
):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return
self
.initial[
"password"
]
class
MyUserAdmin(UserAdmin):
# The forms to add and change user instances
form
=
UserChangeForm
add_form
=
UserCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display
=
(
'email'
,
'date_of_birth'
,
'is_admin'
)
list_filter
=
(
'is_admin'
,)
fieldsets
=
(
(
None
, {
'fields'
: (
'email'
,
'password'
)}),
(
'Personal info'
, {
'fields'
: (
'date_of_birth'
,)}),
(
'Permissions'
, {
'fields'
: (
'is_admin'
,)}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets
=
(
(
None
, {
'classes'
: (
'wide'
,),
'fields'
: (
'email'
,
'date_of_birth'
,
'password1'
,
'password2'
)}
),
)
search_fields
=
(
'email'
,)
ordering
=
(
'email'
,)
filter_horizontal
=
()
# Now register the new UserAdmin...
admin.site.register(MyUser, MyUserAdmin)
# ... and, since we're not using Django's built-in permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)
|
最后,别忘了在settings.py中定义AUTH_USER_MODEL:
1
|
AUTH_USER_MODEL
=
'customauth.MyUser'
|