這篇會比較長一點,因為要用到前幾篇的functions。
1.
[Registration]
Django的用戶登記、認證、註冊⋯等等都是由
django.contrib.auth
打理。
用戶註冊的程序比起登入要繁複一點,但logic大致相同。
首先到
urls.py
加入連結方式:
urlspattern=[
...
...
url(r'^registration/$', registration, name='registration'),
]
因為我們之前註冊用戶是在terminal使用
createsuperuser
,所以在設定views.py之前,要先建立一套form給用戶作自己註冊。
正如之前提及,所有用戶的都經由django.contrib.auth打理,所以註冊用戶時我們要用到的有:
- django.contrib.auth.models.User
- django.contrib.auth.forms.UserCreationForm
- django.forms
UserCreationForm
是Django built-in的註冊用戶表單,其實我們可以使用Django內建的去註冊帳戶。
可是因為原有的註冊不要求email address,跟我們real practice有點脫節的感覺,
所以像之前的
POST FORM一樣,我們還是自己重建較好。
2.
[Create new form]
到
forms.py
建立form class Registraion:
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django import forms
class Registration(UserCreationForm):
username = forms.CharField(required=True, widget=forms.TextInput(attrs={'autofocus':'autofocus'}))
email = forms.EmailField(required=True, help_text='Valid Email Required.')
password1 = forms.CharField(required=True, help_text='At Least 8 Chars with aplabets + numbers', max_length=8, widget=forms.PasswordInput)
class Meta:
model = User
fields = (username, email, password1, password2)
就這樣,我們重新定義了幾個fields,包括username,email及password1。
/* Django 本來就有兩個password,一個叫password1,另一個叫password2作confirmation用 */
上面重新定義form時,有幾點值得留意:
- 把email都變成
required=True
,即必需項目,
還加入help_text準備讓HTML顯示出黎。
- 另外我們還在username及password1引入了widget,目的是更改它們既有的form種類。
例如password1改成PasswordInput,用家在輸入表格時,密碼會自己遮閉,變成我們熟識的「....」
- widget另一個好處是可以為表格增加attributes,例如size, rows, cols, resize, autofocus等等,
原理其實是把它看成HTML5裡的<Input>,以username為例:<input type='text' autofocus>這樣意思。
/* 有關django forms的fields還有widget的種類,可以參考Forms Fields以及Forms Widgets */
3.
[Create view function]
到
views.py
編寫之前,我們先草擬一下要寫一個怎樣的
Register function:
- 從
urls
接收到要運行views的command, 而views.Register
連接HTML template - templates/account/registration.html
- 如果用戶已登入,回傳到首頁
- 設定一個subclass為我們剛寫的class - forms.Registration:
form = forms.Registration()
- 當用戶使用POST METHOD送出資料時,要審查一下form裡面的資料正確性:
form.is_valid()
- 審查email address有沒有重覆,
因為Django只會查核username是否唯一,所以我們要手動加入這項檢查,
checkfault, error = form.clean_user(),要再到
forms.py
增加clean_user function
- 如全部資料正確,把用戶登入,回傳到首頁
可以參考Day4 - Custom Login Page and Logout如何把用戶登入
- 發送email至新用戶,修改及利用
views.sendmail
簡單發送email 功能views.sendmail
可以參考Day6 - Send Emails (python-decouple)
- 如有資料出錯,在註冊頁顯示error
/* 要留意紅字,等等我會需要到forms.py
再作修改以配合使用。 */
了解好了,就到
views.py
編寫新function -
Register:
from django.shortcuts import render
from django.contrib.auth.models import User
from django.contrib import auth
from .forms import Registration
def Register(request):
if request.user.is_authenticated:
return blogindex(request)
if request.method == "POST":
form = Registration(request.POST)
if form.is_valid():
checkfault, error = form.clean_user()
if checkfault == True:
form = Registration()
return render(request, 'account/registration.html', {'form':form, 'errorcode':error})
else:
user.form.save()
username = request.POST.get('username')
password = request.POST.get('password1')
user = auth.authenticate(username=username, passowrd=password)
auth.login(request, user)
title = 'registration'
return sendmail(request, title=title)
else:
form = Registration()
error = 'There is something wrong about your information.'
return render(request, 'account/registration.html', {'form':form, 'errorcode':error})
else:
form = Registration()
return render(request, 'account/registration.html', {'form':form})
上面的
views.Register
引用了兩個額外的functions:
forms.clean_user()
views.sendmail()
所以接下來要到
forms.Registration
及
views.sendmail
做少少修改。
4.
[Create form method]
到
forms.py
裡面,找到我們一開始寫的class Registration。
在裡面,新增一個Form method -
clean_user:
from django.contrib.auth.models import User
class Registration(UserCreationForm):
def clean_user(self):
form_data = self.cleaned_data
fault = True
error = ''
if User.objects.get(form_data['email']).count() > 0:
error = 'Email Already Exits!'
return fault, error
else:
fault = False
return fault, error
這樣
views.Register
裡面的
form是subclass,就可以使用superclass的功能
clean_user()了。
當使用時,
self.cleaned_data
就是
form.cleaned_data
這意思,
作用是在
form.is_valid()通過下,進一步肯定資料是合格,符合python套用。
/* 一般的填漏資料、字數錯誤等等,會在is_valid()下排除了 */
cleaned_data後,我們利用
User.objects.get()
及
.count()
就可以數到User models裡面,有多少個使用了一樣的email address。
當發現重複的email address時,它會回傳
fault=True &
error = 'Email Already Exits!'到step 4 的
view.Register
為
checkfault, error。
5.
[Modify view for email]
當資料完全合格時,我們的
views.Register
會使用
form.save()註冊及把用戶登入。
此外還會把一個叫
title的parameter,傳到
sendmail function,作發送註冊確認email。
所以我們新建或修改
views.py
的
sendmail內容,變成這樣:
from django.template.loader import render_to_string
from django.core.mail import send_mail
def sendmail(request, title=title)
recipient = request.user.email
if title == 'registration':
email_title = "Confirmation of Registration at XXX website"
email_content = render_to_string('account/registration.txt', {'username':request.user.username})
send_mail(
email_title,
‘’,
'<yourmail>@gmail.com',
[recipient,],
html_message=email_content
)
return blogindex(request)
這樣就會發送email到註冊用戶了!。。。不過還沒有內容
上面使用了
django.template.loader.render_to_string
這個功能,它會把一個名為
account/registration.txt
的txt file內容加到parameter
email_content。
所以要建立這個txt file,內容就是email內容:
e.g.
{% autoescape off %}
Hello <span style='color: blue'>{{ username }}! </span>
Nice to meet you!
Welcome to our site and we want to <span style='color: red'>Thank You</span> for registering!
Cheers,
xxx Team
{% endautoescape %}
這裡用了
{% autoescape off %} 是以防文件內容需要用到HTML/CSS,例如連結、字體等可以正常顯示。
6.
[Templates]
還差甚麼? 就是一頁
account/registration.html
。
它的內容很簡單:
{% extends 'base.html' %}
{% block content %}
<form method="POST">
{% csrf_token %}
{% for field in form %}
<label for='username'>{{ field.label_tag }}</label>{{ field }}
{% if {{ field.help_text }} %}
{{ field.help_text }}
{% endif %}
{% endfor %}
<input type='submit' value='Sign Up'>
</form>
{% endblock %}
終於,Registration + email confirmation完成了。
/* 當然可以用HTML + CSS把這頁美化一下。 */