1. 程式人生 > >Django 2.0 專案實戰: 擴充套件Django自帶User模型,實現使用者註冊與登入

Django 2.0 專案實戰: 擴充套件Django自帶User模型,實現使用者註冊與登入

使用者的註冊與登陸是一個網站應該具有的基本功能。網上很多Django關於實現使用者註冊與登入的教程都是用Django 1.X寫的,比較老了,所以小編我覺得有必要親自動手用Django 2.0重寫使用者註冊與登陸教程。另外網上很多教程忽略了Django Auth模組自帶的User模型而重新建立了自己使用者的模型,小編我一看到這種教程就會投去一臉鄙視的目光。一個網站會什麼要有兩個User模型? Why? Why? 本文會教你在不自建User模型的情況下實現使用者的註冊與登陸。另外,我們會對Django Auth自帶的User模型進行擴充套件,允許使用者新增更多的個人資訊。由於全文非常的長,我們會分3部分推送,歡迎訂閱我的微信公眾號【

Python與Django大咖之路】獲取最新文章。

總體開發思路

我們要利用Django 2.0開發一個叫users的app,來實現以下6項功能。我們一共將分3篇文章來介紹。本文只介紹使用者的註冊登入部分。

  • 使用者註冊: 註冊完成後轉到登入頁面 

  • 使用者登入: 登入完成後轉到使用者資料頁面

  • 使用者資料頁面: 檢視使用者註冊資訊,並提供編輯資料按鈕

  • 使用者資料編輯:編輯完成後轉到使用者資料檢視頁面

  • 使用者密碼重置

  • 使用者退出登陸

由於Django Auth自帶的User模型欄位有限,我們還需要自定義模型UserProfile對其擴充套件。

Django Auth模組自帶User模型所包含欄位

  • username:使用者名稱

  • email: 電子郵件

  • password:密碼

  • first_name:名

  • last_name:姓

  • is_active: 是否為活躍使用者。預設是True

  • is_staff: 是否為員工。預設是False

  • is_superuser: 是否為管理員。預設是False

  • date_joined: 加入日期。系統自動生成。

自定義的UserProfile模型

  • user: 與User是1對1關係

  • org:使用者名稱

  • telephone: 電話

  • mod_date: 最後修改日期。系統自動生成

第一步: 建立名叫users的app並修改設定setting.py

我們假設你已經利用Django建立了一個叫mysite的專案,你可以在終端cmd視窗cd進入這個目錄,並輸入以下命令建立一個叫

users的app。

python manage.py startapp users

然後找到mysite/settings.py裡將'users' 加到INSTALLED_APPS裡,如下圖所示。

INSTALLED_APPS = [
   'reg.apps.RegConfig',
   
'django.contrib.admin',
   
'django.contrib.auth',
   
'django.contrib.contenttypes',
   
'django.contrib.sessions',
   
'django.contrib.messages',
   
'django.contrib.staticfiles',
   
'users',
]

第二步: 建立名叫UserProfile的模型(Model)

我們並沒有改變Django Auth自帶的User模型,也沒有建立新的User模型。UserProfile只是對User模型的擴充套件。找到users/models.py, 並建立如下UserProfile模型。由於我們引用了Django Auth自帶的User模型,所以我們必需開始先把它import進來。


from
django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):

   user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')

   org = models.CharField(
       'Organization', max_length=128, blank=True)

   telephone = models.CharField(
       'Telephone', max_length=50, blank=True)

   mod_date = models.DateTimeField('Last modified', auto_now=True)

   class Meta:
       verbose_name = 'User Profile'

   
def __str__(self):return self.user.__str__()

然後你可以在終端輸入以下命令,就可以建立UserProfile的資料表。

python manage.py makemigrations
python manage.py migrate

第三步:配置URL

小編我是自上而下思考的,所以我習慣上先編寫URL,再寫檢視view。從URL配置上你應該可以直接理解我們想實現的6個功能。下面是users/urls.py裡的全部程式碼。你應該注意到,我們給動態連結/register/取了個名字’register', 這樣我們就可以在html模板裡可以通過{% url 'users:register' %}呼叫這個連結了。

from django.urls import re_path
from . import views

app_name = 'users'
urlpatterns = [
   re_path(r'^register/$', views.register, name='register'),
   
re_path(r'^login/$', views.login, name='login'),
   
re_path(r'^user/(?P<pk>\d+)/profile/$', views.profile, name='profile'),
   
re_path(r'^user/(?P<pk>\d+)/profile/update/$', views.profile_update, name='profile_update'),
   
re_path(r'^user/(?P<pk>\d+)/pwdchange/$', views.pwd_change, name='pwd_change'),
   
re_path(r'^logout/$', views.logout, name='logout'),
]

另外找到mysite/urls.py, 把我們這個app的URLs也加進去,如下圖所示。這樣當用戶訪問/accounts/register/時,瀏覽器會呼叫views.py裡的register函式。

urlpatterns = [url(r'^admin/', admin.site.urls),
   
url(r'^accounts/', include('users.urls')),

]

第四步: 編寫試圖(view)

我們需要編寫register和login兩個檢視, 讓使用者通過表單向我們提交資料,並處理這些資料。因為這兩個檢視都需要用表單,所以我們先在users目錄下新建forms.py, 然後建立兩個form,一個RegistrationForm,一個LoginForm程式碼如下:

from django import forms
from django.contrib.auth.models import User
import re


def email_check(email):
   pattern = re.compile(r"\"?([-a-zA-Z0-9.`?{}][email protected]\w+\.\w+)\"?")
   return re.match(pattern, email)


class RegistrationForm(forms.Form):

   username = forms.CharField(label='Username', max_length=50)
   email = forms.EmailField(label='Email',)
   password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
   password2 = forms.CharField(label='Password Confirmation', widget=forms.PasswordInput)

   # Use clean methods to define custom validation rules

   
def clean_username(self):
       username = self.cleaned_data.get('username')

       if len(username) < 6:
           raise forms.ValidationError("Your username must be at least 6 characters long.")
       elif len(username) > 50:
           raise forms.ValidationError("Your username is too long.")
       else:
           filter_result = User.objects.filter(username__exact=username)
           if len(filter_result) > 0:
               raise forms.ValidationError("Your username already exists.")

       return username

   def clean_email(self):
       email = self.cleaned_data.get('email')

       if email_check(email):
           filter_result = User.objects.filter(email__exact=email)
           if len(filter_result) > 0:
               raise forms.ValidationError("Your email already exists.")
       else:
           raise forms.ValidationError("Please enter a valid email.")

       return email

   def clean_password1(self):
       password1 = self.cleaned_data.get('password1')


if len(password1) < 6:
           raise forms.ValidationError("Your password is too short.")
       elif len(password1) > 20:
           raise forms.ValidationError("Your password is too long.")

       return password1

   def clean_password2(self):
       password1 = self.cleaned_data.get('password1')
       password2 = self.cleaned_data.get('password2')

       if password1 and password2 and password1 != password2:
           raise forms.ValidationError("Password mismatch. Please enter again.")

       return password2


class LoginForm(forms.Form):

   username = forms.CharField(label='Username', max_length=50)
   password = forms.CharField(label='Password', widget=forms.PasswordInput)

   # Use clean methods to define custom validation rules

   
def clean_username(self):
       username = self.cleaned_data.get('username')

       if email_check(username):
           filter_result = User.objects.filter(email__exact=username)
           if not filter_result:
               raise forms.ValidationError("This email does not exist.")
       else:
           filter_result = User.objects.filter(username__exact=username)
           if not filter_result:

raise forms.ValidationError("This username does not exist. Please register first.")

       return username

千萬不要上面的程式碼嚇到。之所以程式碼這麼長是因為我們用clean方法加入了很多表單驗證項,比如檢查使用者名稱是否過短,使用者名稱是否已經存在。如果你把表單驗證拿掉,其實程式碼非常少。我之所以加上這些驗證規則,是讓你瞭解最真實的網站開發。

當然你也可以不用新建forms.py而直接在html模板裡寫表單,但我並不建議這麼做。用forms.py的好處顯而易見: 

  • 所有的表單在一個檔案裡,非常便於後期維護,比如增添或修訂欄位。

  • forms.py可通過clean方法自定義表單驗證,非常便捷。不用在views.py裡再進行表單驗證(比如檢查使用者是否已存在),邏輯上更清晰。

我們的檢視users/views.py是這樣子的。

from django.shortcuts import render, get_object_or_404
from django.contrib.auth.models import User
from .models import UserProfile
from django.contrib import auth
from .forms import RegistrationForm, LoginForm, ProfileForm, PwdChangeForm
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth.decorators import login_required


def register(request):
   if request.method == 'POST':

       form = RegistrationForm(request.POST)
       if form.is_valid():
           username = form.cleaned_data['username']
           email = form.cleaned_data['email']
           password = form.cleaned_data['password2']

           # 使用內建User自帶create_user方法建立使用者,不需要使用save()
       
user = User.objects.create_user(username=username, password=password, email=email)

           # 如果直接使用objects.create()方法後不需要使用save()
       
user_profile = UserProfile(user=user)
           user_profile.save()

           return HttpResponseRedirect("/accounts/login/")

   else:
       form = RegistrationForm()

   return render(request, 'users/registration.html', {'form': form})


def login(request):
   if request.method == 'POST':
       form = LoginForm(request.POST)
       if form.is_valid():

          username = form.cleaned_data['username']
          password = form.cleaned_data['password']

          user = auth.authenticate(username=username, password=password)

          if user is not None and user.is_active:
              auth.login(request, user)
              return HttpResponseRedirect(reverse('users:profile', args=[user.id]))

           else:
               # 登陸失敗
          
return render(request, 'users/login.html', {'form': form,
                             
'message': 'Wrong password. Please try again.'})
   else:
       form = LoginForm()

   return render(request, 'users/login.html', {'form': form})

我們先看下views.register函式是怎麼工作的:

  • 當用戶通過POST方法提交表單,我們先驗證表單RegistrationForm的資料是否有效。如果有效,我們先用Django User模型自帶的create_user方法建立user物件,再建立user_profile。使用者通過一張表單提交資料,我們實際上分別儲存在兩張表裡。

  • 如果使用者註冊成功,我們通過HttpResponseRedirect方法轉到登陸頁面

  • 如果使用者沒有提交表單或不是通過POST方法提交表單,我們轉到註冊頁面,生成一張空的RegistrationForm

我們再看下views.login函式是怎麼工作的:

  • 當用戶通過POST方法提交表單,我們先驗證表單LoginForm的資料是否有效。如果有效,我們呼叫Django自帶的auth.authenticate() 來驗證使用者名稱和密碼是否正確。如果正確且使用者是活躍的,我們呼叫auth.login()來進行登入。

  • 如果使用者登入失敗,會重新轉到登入頁面,並返回錯誤資訊。

  • 如果使用者登入成功,我們通過HttpResponseRedirect方法轉到使用者個人資訊頁面

  • 如果使用者沒有提交表單或不是通過POST方法提交表單,我們轉到登入頁面,生成一張空的LoginForm

第五步: 編寫HTML模板(Template)

在users目錄下建立/templates/users/資料夾,編寫html模板registration.htmllogin.html。其目錄結構應該如下圖所示:

下面是模板registration.html的程式碼:

{% block content %}
<div class="form-wrapper">
  <form
method="post" action="" enctype="multipart/form-data">
     
{% csrf_token %}
     {% for field in form %}
          <div class="fieldWrapper">
       
{{ field.errors }}
       {{ field.label_tag }} {{ field }}
       {% if field.help_text %}
            <p class=

相關推薦

Django 2.0 專案實戰: 擴充套件DjangoUser模型實現使用者註冊登入

使用者的註冊與登陸是一個網站應該具有的基本功能。網上很多Django關於實現使用者註冊與登入的教程都是用Django 1.X寫的,比較老了,所以小編我覺得有必要親自動手用Django 2.0重寫使用者註

Django 2.0 專案實戰 (3): 使用者重置密碼退出登入

在之前兩篇文章中我們擴充套件了Django自帶的User模型並實現了使用者的登入與註冊,並同時實現了檢視和編輯使用者個人資料的功能。本文是Django實現使用者註冊登入系列教程的最後一篇,我們將會開發兩

django 擴充套件DjangoUser模型實現使用者註冊登入

from django import forms from django.contrib.auth.models import User import re def email_check(email):    pattern = re.compile(r"\"?([-a-zA-Z0-9.`?{}][e

Django學習筆記(16)——擴充套件DjangoUser模型實現使用者註冊登入

一,專案題目:擴充套件Django自帶User模型,實現使用者註冊與登入   我們在開發一個網站的時候,無可避免的需要設計實現網站的使用者系統。此時我們需要實現包括使用者註冊,登入,使用者認證,登出,修改密碼等功能。Django作為一個完美主義者的終極框架,當然也會想到使用者的這些痛點,它內建了強大的使用者

Django 2.0 專案配置檔案介紹:

Django專案配置檔案為setting,如下: 其各部分內容含義如下: BASE_DIR:專案檔案路徑,專案建立之後自動設定,不需要改動。 SECRET_KEY:金鑰,專案建立之後自動設定,不需要改動。 DEBUG:供開發人員用,專案結束後,需要將其設定為False。

《阿里巴巴Java Spring Boot 2.0開發實戰課程》05課:三層MVC網站架構分層誤區、Java面試題

《阿里巴巴Java Spring Boot 2.0開發實戰課程》05課本期分享專家:徐雷—阿里特邀Java講師,MongoDB講師 本期分享主題:三層架構MVC網站與分層架構誤區、Java面試題 國內系統架構設計的文章和書籍。經常會搞錯分層的概念,本課程進行了講解。還有關於model概念的解析,以及Jav

android 呼叫系統錄音實現語音錄製播放

相關許可權:<uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission> <uses-permission android:name="and

django 2.0 + Python 3.7 + MySQL 8.0 安裝專案筆記

2018-09-17 11:25安裝Django 2.0 開啟專案 Esale 1.使用開發環境:PyCharm 2018.2.3 (Professional Edition)Build #PY-182.4323.49, built on September 4,

Django專案(2)-定義User模型

需要自定義User模型的原因 需要前後臺共同同一個賬號。 欄位需要自己定義,以及驗證也需要自己設定 from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUse

[Django 2.0] 定義靜態資料夾路徑

今天做部落格的時候對於靜態檔案以及路徑問題有過些疑惑。解決後做一下心得和記錄。在應用設定中,有些靜態的檔案不想放在專案的 static 資料夾中。1.建立文章物件class Arctics(models.Model): title = models.CharField

Django 2.0 Release note閱讀簡記

ast 參數 model release color 變化 則表達式 sql語言 正則表達式 最前面就是大家都知道的這個版本開始只支持py3.4+,而且下一個大版本就不支持3.4,再就是建議所有插件開始放棄1.11 1、最驚艷的變化,就是URL配置正則

Django 2.0.3 使用筆記

復數 imp ural 3.5 個人博客 con ron 中文名 字段 運行環境: Python 3.5.2 Django 2.0.3 Django Admin中model顯示為中文 定義model時,定義一個Meta對象,設置需要顯示的中文名稱。verbose_name

Django 2.0.3安裝-壓縮包方式

dmi 鏈接 script 否則 RM 兩種 建立 djang .py OS:Windows 10家庭中文版,CPU:Intel Core i5-8250U Python版本:Python 2.7,Python 3.6 Django版本:2.0.3(最新2.0.5) 解壓工

vue2 + iview-admin 1.3 + django 2.0 一個最簡單的增刪改查例子

iview-admin axios django 前後端分離 api 以下為利用iview-admin + django 做的一個最基本的增刪改查例子。 前端iview-admin git clone https://github.com/iview/iview-admin.git cd

iview-admin 1.3 + django 2.0 (二) 用戶登錄

iview-admin django 用戶登錄 cookies Iview-admin logo.vue <Alert v-show="isshow" type="error" show-icon closable> 提交錯誤 <span slot="desc

Django 2.0官方文檔中文 渣翻 總索引(個人學習歡迎指正)

裝飾 csr porting other 步驟 exe 擴展 生產 blank Django 2.0官方文檔中文 渣翻 總索引(個人學習,歡迎指正) 置頂 2017年12月08日 11:19:11 閱讀數:20277 官方原文: https://docs.dja

django 2.0.3 Django出錯提示TemplateDoesNotExist at /

這個錯誤筆者在學習django時莫名其妙就產生了,經過幾個小時的折騰總算是弄好了。 一開始我的settings.py 如下 和常規的django配置一樣,DIRS中什麼也沒填,本來好好的,但是突然在學習模板的時候,我有了一個新想法,把DIRS列表中的值加了一個錯誤的值就出錯了,這直接導致了我

Django 2.0 新款URL配置詳解

Django2.0釋出後,很多人都擁抱變化,加入了2的行列。 但是和1.11相比,2.0在url的使用方面發生了很大的變化,下面介紹一下: 一、例項 先看一個例子: from django.urls import path from . import views urlpattern

【轉載】Django 2.0版本的新特性

2017年12月2日,Django官方釋出了2.0版本,成為多年來的第一次大版本提升,那麼2.0對廣大Django使用者有哪些變化和需要注意的地方呢? 一、Python相容性 Django 2.0支援Python3.4、3.5和3.6。Django官方強烈推薦每個系

ASP.NET Core 實戰:將 .NET Core 2.0 專案升級到 .NET Core 2.1

 一、前言    最近一兩個星期,加班,然後回去後弄自己的部落格,把自己的電腦從 Windows 10 改到 Ubuntu 18.10 又弄回 Windows 10,原本計劃的學習 Vue 中生命週期的相關知識目前也沒有任何的進展,嗯,罪過罪過。看了眼時間,11月也快要結束了,準備補上一