Django 中的 django.contrib.auth
應用提供了完整的用戶及認證受權功能。html
Django 官方推薦基於內置 User 數據模型建立新的自定義用戶模型,方便添加 birthday
等新的用戶字段和功能。python
本文包含的內容有:django
django.contrib.auth
應用使用的模板文件。如下全部示例在 Python 3.8.2 + Django 2.1 中實現。bash
$ python manage.py startapp accounts
將應用添加到項目中:app
# project_dir/settings.py INSTALLED_APPS = [ # Local 'accounts.apps.AccountsConfig', #... ]
Django 官方文檔中推薦基於 AbstractBaseUser 建立自定義用戶模型,可是通常基於 AbstractUser 建立再方便。post
本命中的自定義 CustomUser 中新增了字段 birthday。ui
# accounts/models.py from django.db import models from django.contrib.auth.models import AbstractUser class CustomUser(AbstractUser): birthday = models.DateField(null=True, blank=True)
經過 AUTH_USER_MODEL
告訴系統新的用戶模型:url
# project_dir/settings.py AUTH_USER_MODEL = 'accounts.CustomUser'
以後可經過 get_user_model()
獲取該自定義用戶模型:spa
# in view or model files from django.contrib.auth import get_user_model CustomUser = get_user_model()
django.contrib.auth
應用已實現了完整的 login, logout 功能,並已在 django.contrib.auth.urls
中定義了 login, logout, password_change, password_change_done, password_reset, password_reset_done, password_reset_confirm, password_reset_complete 等 URL。code
將 django.contrib.auth.urls
集成到項目中:
# project_dir/urls.py from django.urls import path, include urlpatterns = [ path('accounts/', include('django.contrib.auth.urls'), #... ]
集成後,便可訪問 /accounts/login/
, /accounts/logout/
, /accounts/password_change/
等功能,同時時視圖和模板中也可訪問這個 URL 定義:
<!-- in template files --> <a href="{% url 'login' %}">Login URL</a>
# in view files from django.urls import reverse, reverse_lazy login_url = reverse('login') #in Class Based View: login_url = reverse_lazy('login')
後臺管理界面中,添加新用戶時呈現的表單由 django.contrib.auth.forms.UserCreationForm
提供,而更新用戶時呈現的表單由 django.contrib.auth.forms.UserChangeForm
提供。
爲自定義用戶模型定製這兩個表單:
# accounts/forms.py from django.contrib.auth.forms import UserCreationForm, UserChangeForm from .models import CustomUser class CustomUserCreationForm(UserCreationForm): class Meta(UserCreationForm.Meta): model = CustomUser fields = ('username', 'email', 'birthday', ) class CustomUserChangeForm(UserChangeForm): class Meta(UserChangeForm.Meta): model = CustomUser fields = UserChangeForm.Meta.fields + ( 'birthday', )
註冊到 admin 中:
# accounts/admin.py from django.contrib import admin from django.contrib.auth.admin import UserAdmin from .models import CustomUser from .forms import CustomUserCreationForm, CustomUserChangeForm class CustomUserAdmin(UserAdmin): model = CustomUser add_form = CustomUserCreationForm form = CustomUserChangeForm list_display = ['email', 'username', 'birthday', 'is_staff'] admin.site.register(CustomUser, CustomUserAdmin)
django.contrib.auth
應用使用的模板文件django.contrib.auth
中 login, logout, password_change, password_change_done, password_reset, password_reset_done, password_reset_confirm, password_reset_complete 等視圖,訪問的相應模板需保存在registration/
目錄下,模板文件有: login.html, password_change_done.html, password_change_form.html, password_reset_complete.html, password_reset_confirm.html, password_reset_done.html, password_reset_form.html 等。
默認配置下,模板文件需保存在 <app-name>/templates/<app-name>/registration/
目錄下,如 accounts/templates/accounts/registration/login.html
。
對於小項目,能夠將模板目錄設置爲扁平化:
# project_dir/settings.py TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], # new #... } ]
從而模板能夠保存在 templates/
目錄中,如 templates/registration/login.html
。
模板中可以使用 form
變量,例如:
<!-- templates/registration/login.html --> {% extends 'base.html' %} {% block title %}Login{% endblock title %} {% block content %} <h2>Login</h2> <form method="post"> {% csrf_token %} {{ form.as_p }} <button class="btn btn-success ml-2" type="submit">Login</button> </form> {% endblock content %}
django.contrib.auth
沒有實現 sign up 功能。
基於 CreateView 建立 SignUpView 視圖:
# accounts/views.py from django.views.generic.edit import CreateView from django.urls import reverse_lazy from .models import CustomUser from .forms import CustomUserCreationForm class SignupView(CreateView): #model = CustomUser form_class = CustomUserCreationForm template_name = 'signup.html' success_url = reverse_lazy('login')
添加模板文件:
<!-- templates/signup.html --> {% extends 'base.html' %} {% load crispy_forms_tags %} {% block title %}Signup{% endblock title %} {% block content %} <h2>Signup</h2> <form method="post"> {% csrf_token %} {{ form|crispy }} <button class="btn btn-success" type="submit">Signup</button> </form> {% endblock content %}
添加應用級別的 URL 配置:
# accounts/urls.py from django.urls import path from .views import SignUpView urlpatterns = [ path('signup/', SignUpView.as_view(), name='signup'), ]
集成到項目級別的 URL 配置中:
# project_dir/urls.py urlpatterns = [ path('admin/', admin.site.urls), path('accounts/', include('accounts.urls')), path('accounts/', include('django.contrib.auth.urls')), #... ]
視圖應繼承加入 LoginRequiredMixin
,屬性值 login_url
設置當沒有登陸時,將轉向的登陸頁面地址或 URL name:
# in view files from django.views.generic.edit import DeleteView from django.urls import reverse_lazy from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import PermissionDenied from .models import Article class ArticleDeleteView(LoginRequiredMixin, DeleteView): model = Article template_name = 'article_delete.html' success_url = reverse_lazy('article_list') login_url = 'login'
CBV 中,代碼調用入口是 dispatch()
方法,能夠在該方法中實現權限驗證,當權限不夠時拋出異常:
# in view files from django.views.generic.edit import DeleteView from django.urls import reverse_lazy from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import PermissionDenied from .models import Article class ArticleDeleteView(LoginRequiredMixin, DeleteView): model = Article template_name = 'article_delete.html' success_url = reverse_lazy('article_list') login_url = 'login' def dispatch(self, request, *args, **kwargs): obj = self.get_object() if obj.author != request.user: raise PermissionDenied() return super().dispatch(request, *args, **kwargs)