用戶註冊登錄是一個網站的基本功能,django對這部分進行了很好的封裝,我們只需要在django的基礎上做些簡單的修改就可以達到我們想要的效果。在本講中,我們會用到user中的用戶授權方面的一些函數,還會對django中的user進行擴展,以及django中的form驗證。
效果展示
註冊頁面
登錄頁面
創建users應用
django的設計哲學是,一個應用只提供一種功能,比如users應用只提供用戶相關功能,comment應用只提供評論相關功能,這能提高代碼的重複利用率。
在django中,只需要下面一條命令,即可建立users應用
python3 manage.py startapp users
建表
我們需要一個用戶表,用來實現登錄註冊功能,雖然django已經自帶來用戶登錄註冊功能,也有相應的表,但是不符合中國人習慣,需要我們對user模型進行自定義。實現自定義User模型最簡單的方式就是繼承AbstractBaseUser,AbstractBaseUser實現了User的核心功能,我們只需加一些額外的字段進行補充即可。
User模型原有的字段有:
- username
- password
- last_login
- is_superuser
- first_name
- last_name
- is_staff
- is_active
- date_joined
這些都是最基本的字段,並不能滿足我們的需求。
根據網站自身業務,我們又添加了下面的字段
- nickname(暱稱)
- avatar(頭像)
- mobile(手機號)
- gender(性別)
- subscribe(是否訂閱)
我們只需在users/models.py中寫入代碼
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
GENDER_CHOICES = (
('M', '男'),
('F', '女'),
)
nickname = models.CharField(blank=True, null=True, max_length=20)
avatar = models.FileField(upload_to='avatar/')
mobile = models.CharField(blank=True, null=True, max_length=13)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES,blank=True, null=True)
subscribe = models.BooleanField(default=False)
class Meta:
db_table = "v_user"
gender是性別字段,其中用到了choices=GENDER_CHOICES。這種方式常常用在下拉框或單多選框,例如 M對應男 F對應女。
url配置
在user文件夾下面,新建url.py文件,寫入登錄、註冊和退出的url信息。app_name是命名空間,我們命名爲'users'。
from django.urls import path
from . import views
app_name = 'users'
urlpatterns = [
path('login/', views.login, name='login'),
path('signup/', views.signup, name='signup'),
path('logout/', views.logout, name='logout'),
]
url路由配置好了,我們下面就開始寫視圖函數代碼了
註冊函數
我們先來寫註冊函數,寫註冊,當然得有註冊表單了,幸運的是,在django中,可以用代碼來生成表單。我們只需在users下新建forms.py文件,然後寫入註冊表單的代碼。
class SignUpForm(UserCreationForm):
username = forms.CharField(min_length=4,max_length=30,
error_messages={
'min_length': '用戶名不少於4個字符',
'max_length': '用戶名不能多於30個字符',
'required': '用戶名不能爲空',
},
widget=forms.TextInput(attrs={'placeholder': '請輸入用戶名'}))
password1 = forms.CharField(min_length=8, max_length=30,
error_messages={
'min_length': '密碼不少於8個字符',
'max_length': '密碼不能多於30個字符',
'required': '密碼不能爲空',
},
widget=forms.PasswordInput(attrs={'placeholder': '請輸入密碼'}))
password2 = forms.CharField(min_length=8,max_length=30,
error_messages={
'min_length': '密碼不少於8個字符',
'max_length': '密碼不能多於30個字符',
'required': '密碼不能爲空',
},
widget=forms.PasswordInput(attrs={'placeholder': '請確認密碼'}))
class Meta:
model = User
fields = ('username', 'password1', 'password2',)
error_messages = {'password_mismatch': '兩次密碼不一致', }
我們的表單一共有三個字段:username、password1、password2,它們都是CharField類型,widget分別是TextInput和PasswordInput。而且django是自帶驗證的,只需要我們配置好error_messages字典,當form驗證的時候,就會顯示我們自定義的錯誤信息。
有了註冊表單後,就可以在前端模板和視圖函數中使用它。
下面是註冊視圖函數。
...
from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
raw_password1 = form.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password1)
auth_login(request, user)
return redirect('home')
else:
print(form.errors)
else:
form = SignUpForm()
return render(request, 'registration/signup.html', {'form': form})
在signup函數中,我們通過form = SignUpForm初始化一個表單,並在render函數中傳遞給模板。
註冊模板文件寫在了templates/registration/signup.html
關鍵代碼是
<form class="ui large form" novalidate method="post" action="{% url 'users:signup' %}" enctype="multipart/form-data" >
{% csrf_token %}
<div class="ui stacked segment">
<div class="field">
{{form.username}}
</div>
<div class="field">
{{form.password1}}
</div>
<div class="field">
{{form.password2}}
</div>
<button class="ui submit button" type="submit">註冊</button>
</div>
{% include "base/form_errors.html" %}
</form>
form的action爲
{% url 'users:signup' %}
即在url.py中定義的signup函數。
通過post請求傳遞給signup,在signup中,通過如下四行代碼來實現註冊,並自動登錄的。
username = form.cleaned_data.get('username')
raw_password1 = form.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password1)
auth_login(request, user)
登錄函數
登錄函數與註冊函數的模式是一樣的,都是先寫form,寫模板,最後寫視圖函數。
由於form和模板的代碼和註冊功能類似,這裏就不貼了,大家可以上github查看。
重點講一下login視圖函數
def login(request):
if request.method == 'POST':
next = request.POST.get('next', '/')
form = UserLoginForm(request=request, data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
auth_login(request, user)
return redirect(next)
else:
print(form.errors)
else:
next = request.GET.get('next', '/')
form = UserLoginForm()
print(next)
return render(request, 'registration/login.html', {'form': form, 'next':next})
在login函數中,我們多了一個next變量,next對應的是登錄後要跳轉的url,其實這是一種場景,假如你在購物網站買東西,最後付款的時候,會跳轉到付款頁,假如你沒有登錄,網站會提示你登錄,登錄後,會再次跳轉到付款頁。
當然了,跳轉到登錄頁的時候,需要你在url後追加next參數,如 aaa. com/login/?next=bbb. com
這樣用戶登錄後就會跳到bbb. com
退出函數
from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout
def logout(request):
auth_logout(request)
return redirect('home')
退出功能,僅需要一行代碼 auth_logout(request) 就ok了。