Django內建的User模型可能不適合某些類型的項目。例如,在某些網站上使用郵件地址而不是用戶名做爲身份的標識可能更合理。python
Django容許你經過修改setting.py文件中的 AUTH_USER_MODEL 設置覆蓋默認的User模型,其值引用一個自定義的模型。git
AUTH_USER_MODEL = 'myapp.MyUser'
上面的值表示Django應用的名稱(必須位於INSTALLLED_APPS中)和你想使用的User模型的名稱。數據庫
注意:
1.在建立任何遷移或者第一次運行 manager.py migrate 前設置 AUTH_USER_MODEL。
設置AUTH_USER_MODEL對你的數據庫結構有很大的影響。它改變了一些會使用到的表格,而且會影響到一些外鍵和多對多關係的構造。在你有表格被建立後更改此設置是不被 makemigrations 支持的,而且會致使你須要手動修改數據庫結構,從舊用戶表中導出數據,可能從新應用一些遷移。django
警告 :
1.確保 AUTH_USER_MODEL 引用的模型在所屬app中第一個遷移文件中被建立
因爲Django的可交換模型的動態依賴特性的侷限,你必須確保 AUTH_USER_MODEL 引用的模型在所屬app中第一個遷移文件中被建立(一般命名爲 0001_initial),不然你會碰到錯誤。數組
The easiest way to construct a compliant custom User model is to inherit fromAbstractBaseUser. AbstractBaseUser provides the core implementation of a Usermodel, including hashed passwords and tokenized password resets. You must then provide some key implementation details:session
在 AUTH_USER_MODEL 設置爲自定義用戶模型時,若是你直接引用User(例如:經過一個外鍵引用它),你的代碼將不能工做。你應該使用django.contrib.auth.get_user_model()來引用用戶模型————指定的自定義用戶模型或者Userapp
from django.contrib.auth import get_user_model User = get_user_model()
當你定義一個外鍵或者到用戶模型的多對多關係是,你應該使用AUTH_USER_MODEL設置來指定自定義的模型。框架
from django.conf import settings from django.db import models class Article(models.Model): author = models.ForeignKey(settings.AUTH_USER_MODEL)
通常來講,在導入時候執行的代碼中,你應該使用 AUTH_USER_MODEL 設置引用用戶模型。get_user_model() 只在Django已經導入全部的模型後才工做。less
USERNAME_FIELD
必須設置。 設置認證標識,設置成標識的字段 unique=Trueide
class MyUser(AbstractBaseUser): identifier = models.CharField(max_length=40, unique=True) ... USERNAME_FIELD = 'identifier'
REQUIRED_FIELDS
必須設置。當經過createsuperuser管理命令建立一個用戶時,用於提示的一個字段名稱列表。
class MyUser(AbstractBaseUser): ... date_of_birth = models.DateField() height = models.FloatField() ... REQUIRED_FIELDS = ['date_of_birth', 'height']
列表中不該該包含USERNAME_FIELD字段和password字段。
is_active
必須定義。 一個布爾屬性,標識用戶是不是 "active" 的。AbstractBaseUser默認爲 Ture。
get_full_name()
必須定義。 long格式的用戶標識。
get_short_name()
必須定義。 short格式的用戶標識。
get_username()
返回 USERNAME_FIELD 的值。
is_anonymous()
一直返回 False。用來區分 AnonymousUser。
is_authenticated()
一直返回 Ture。用來告訴用戶已被認證。
set_password(raw_password)
設置密碼。按照給定的原始字符串設置用戶的密碼,taking care of the password hashing。 不保存 AbstractBaseUser 對象。若是沒有給定密碼,密碼就會被設置成不使用,同用set_unusable_password()。
check_password(raw_password)
檢查密碼是否正確。 給定的密碼正確返回 True。
set_unusable_password()
設置user無密碼。 不一樣於密碼爲空,若是使用 check_password(),則不會返回True。不保存AbstractBaseUser 對象。
has_usable_password()
若是設置了set_unusable_password(),返回False。
get_session_auth_hash()
返回密碼字段的HMAC。 Used for Session invalidation on password change.
若是你的User模型定義了這些字段:username, email, is_staff, is_active, is_superuser, last_login, and date_joined跟默認的User沒什麼區別, 那麼你還不如僅僅替換Django的UserManager就好了; 總之,若是你的User定義了不一樣的字段, 你就要去自定義一個管理器,它繼承自BaseUserManager並提供兩個額外的方法:
create_user(username_field, password=None, other_fields)
接受username field和required字段來建立用戶。例如,若是使用email做爲username field, date_of_birth做爲required field:
def create_user(self, email, date_of_birth, password=None): # create user here ...
def create_superuser(self, email, date_of_birth, password): # create superuser here ...
create_superuser中的password是必需的
若是你徹底滿意Django的用戶模型和你只是想添加一些額外的屬性信息,你只需繼承 django.contrib.auth.models.AbstractUser 而後添加自定義的屬性。AbstractUser 做爲一個抽象模型提供了默認的User的全部的實現(AbstractUser provides the full implementation of the default User as an abstract model.)。
Django內置的forms和views和相關聯的user model有一些先決條件。若是你的user model沒有遵循一樣的條件,則須要定義一個替代的form,經過form成爲身份驗證views配置的一部分。
UserCreationForm
依賴於User Model. 擴展User時必須重寫。
UserChangeForm
依賴於User Model. 擴展User時必須重寫。
AuthenticationForm
Works with any subclass of AbstractBaseUser, and will adapt to use the field defined in USERNAME_FIELD.
PasswordResetForm
Assumes that the user model 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子類
若是你想讓你自定義的User模型也能夠在站點管理上工做,那麼你的模型應該再定義一些額外的屬性和方法。 這些方法容許管理員去控制User到管理內容的訪問:
is_staff
是否容許user訪問admin界面
is_active
用戶是否活躍。
has_perm(perm, obj=None):
user是否擁有perm權限。
has_module_perms(app_label):
user是否擁有app中訪問models的權限
你一樣也須要註冊你自定義的用戶模型到admin。若是你的自定義用戶模型擴展於django.contrib.auth.models.AbscustomauthtractUser,你能夠用django的 django.contrib.auth.admin.UserAdmin 類。若是你的用戶模型擴展於 AbstractBaseUser,你須要自定義一個ModelAdmin類。他可能繼承於默認的django.contrib.auth.admin.UserAdmin。然而,你也須要覆寫一些django.contrib.auth.models.AbstractUser 字段的定義不在你自定義用戶模型中的。
若是想讓在自定義用戶模型中包含Django的權限控制框架變得簡單,Django提供了PermissionsMixin。這是一個抽象的類,你能夠爲你的自定義用戶模型中的類的層次結構中包含它。它提供給你全部Django權限類所必須的的方法和字段
源碼:
class PermissionsMixin(models.Model): """ A mixin class that adds the fields and methods necessary to support Django's Group and Permission model using the ModelBackend. """ is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_('Designates that this user has all permissions without ' 'explicitly assigning them.')) groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True, help_text=_('The groups this user belongs to. A user will ' 'get all permissions granted to each of ' 'their groups.'), related_name="user_set", related_query_name="user") user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True, help_text=_('Specific permissions for this user.'), related_name="user_set", related_query_name="user") class Meta: abstract = True def get_group_permissions(self, obj=None): """ Returns a list of permission strings that this user has through their groups. This method queries all available auth backends. If an object is passed in, only permissions matching this object are returned. """ permissions = set() for backend in auth.get_backends(): if hasattr(backend, "get_group_permissions"): permissions.update(backend.get_group_permissions(self, obj)) return permissions def get_all_permissions(self, obj=None): return _user_get_all_permissions(self, obj) def has_perm(self, perm, obj=None): """ Returns True if the user has the specified permission. This method queries all available auth backends, but returns immediately if any backend returns True. Thus, a user who has permission from a single auth backend is assumed to have permission in general. If an object is provided, permissions for this specific object are checked. """ # Active superusers have all permissions. if self.is_active and self.is_superuser: return True # Otherwise we need to check the backends. return _user_has_perm(self, perm, obj) def has_perms(self, perm_list, obj=None): """ Returns True if the user has each of the specified permissions. If object is passed, it checks if the user has all required perms for this object. """ for perm in perm_list: if not self.has_perm(perm, obj): return False return True def has_module_perms(self, app_label): """ Returns True if the user has any permissions in the given app label. Uses pretty much the same logic as has_perm, above. """ # Active superusers have all permissions. if self.is_active and self.is_superuser: return True return _user_has_module_perms(self, app_label)
源碼:
class AbstractUser(AbstractBaseUser, PermissionsMixin): """ An abstract base class implementing a fully featured User model with admin-compliant permissions. Username, password and email are required. Other fields are optional. """ username = models.CharField(_('username'), max_length=30, unique=True, help_text=_('Required. 30 characters or fewer. Letters, digits and ' '@/./+/-/_ only.'), validators=[ validators.RegexValidator(r'^[\w.@+-]+$', _('Enter a valid username. ' 'This value may contain only letters, numbers ' 'and @/./+/-/_ characters.'), 'invalid'), ], error_messages={ 'unique': _("A user with that username already exists."), }) first_name = models.CharField(_('first name'), max_length=30, blank=True) last_name = models.CharField(_('last name'), max_length=30, blank=True) email = models.EmailField(_('email address'), blank=True) is_staff = models.BooleanField(_('staff status'), default=False, help_text=_('Designates whether the user can log into this admin ' 'site.')) is_active = models.BooleanField(_('active'), default=True, help_text=_('Designates whether this user should be treated as ' 'active. Unselect this instead of deleting accounts.')) date_joined = models.DateTimeField(_('date joined'), default=timezone.now) objects = UserManager() USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['email'] class Meta: verbose_name = _('user') verbose_name_plural = _('users') abstract = True def get_full_name(self): """ Returns the first_name plus the last_name, with a space in between. """ full_name = '%s %s' % (self.first_name, self.last_name) return full_name.strip() def get_short_name(self): "Returns the short name for the user." return self.first_name def email_user(self, subject, message, from_email=None, **kwargs): """ Sends an email to this User. """ send_mail(subject, message, from_email, [self.email], **kwargs) class User(AbstractUser): """ Users within the Django authentication system are represented by this model. Username, password and email are required. Other fields are optional. """ class Meta(AbstractUser.Meta): swappable = 'AUTH_USER_MODEL'
is_superuser
布爾類型。 Designates that this user has all permissions without explicitly assigning them.
get_group_permissions(obj=None)
Returns a set of permission strings that the user has, through their groups.
If obj is passed in, only returns the group permissions for this specific object.
get_all_permissions(obj=None)
Returns a set of permission strings that the user has, both through group and user permissions.
If obj is passed in, only returns the permissions for this specific object.
has_perm(perm, obj=None)
Returns True if the user has the specified permission, where perm is in the format "<app label>.<permission codename>" (see permissions). If the user is inactive, this method will always return False.
If obj is passed in, this method won’t check for a permission for the model, but for this specific object.
has_perms(perm_list, obj=None)
Returns True if the user has each of the specified permissions, where each perm is in the format "<app label>.<permission codename>". If the user is inactive, this method will always return False.
If obj is passed in, this method won’t check for permissions for the model, but for the specific object.
has_module_perms(package_name)
Returns True if the user has any permissions in the given package (the Django app label). If the user is inactive, this method will always return False.
自定義用戶模型的一個限制是安裝自定義用戶模型將破壞任何代理模型擴展User
。代理模型必須基於具體的基類; 經過定義自定義用戶模型,您能夠刪除Django可靠地識別基類的功能。
若是您的項目使用代理模型,則必須修改代理以擴展項目中正在使用的用戶模型,或者將代理的行爲合併到User
子類中。
如下是符合管理員的自定義用戶應用的示例。此用戶模型使用電子郵件地址做爲用戶名,並具備所需的出生日期; 除了admin
用戶賬戶上的簡單標誌以外,它不提供權限檢查。除用戶建立表單外,此模型將與全部內置身份驗證表單和視圖兼容。此示例說明了大多數組件如何協同工做,但不打算直接複製到項目中以供生產使用。
此代碼將存在於models.py
自定義身份驗證應用程序的文件中:
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
而後,要使用Django的admin註冊此自定義用戶模型,應用程序admin.py
文件中將須要如下代碼:
from django import forms from django.contrib import admin from django.contrib.auth.models import Group from django.contrib.auth.admin import UserAdmin as BaseUserAdmin 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 UserAdmin(BaseUserAdmin): # 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, UserAdmin) # ... and, since we're not using Django's built-in permissions, # unregister the Group model from admin. admin.site.unregister(Group)
最後,使用如下AUTH_USER_MODEL
設置將自定義模型指定爲項目的默認用戶模型settings.py
:
1 AUTH_USER_MODEL = 'customauth.MyUser'