🔖 Day7 - Registration (Unique Email) with email confirmation

2018 - 06 - 26
🔖 Day7 - Registration (Unique Email) with email confirmation
這篇會比較長一點,因為要用到前幾篇的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:
  1. urls接收到要運行views的command, 而views.Register連接HTML template - templates/account/registration.html
  2. 如果用戶已登入,回傳到首頁
  3. 設定一個subclass為我們剛寫的class - forms.Registration: form = forms.Registration()
  4. 當用戶使用POST METHOD送出資料時,要審查一下form裡面的資料正確性: form.is_valid()
  5. 審查email address有沒有重覆, 因為Django只會查核username是否唯一,所以我們要手動加入這項檢查, checkfault, error = form.clean_user(),要再到forms.py增加clean_user function
  6. 如全部資料正確,把用戶登入,回傳到首頁 可以參考Day4 - Custom Login Page and Logout如何把用戶登入
  7. 發送email至新用戶,修改及利用views.sendmail 簡單發送email 功能views.sendmail可以參考Day6 - Send Emails (python-decouple)
  8. 如有資料出錯,在註冊頁顯示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.Registrationviews.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.Registercheckfault, error
5. [Modify view for email] 當資料完全合格時,我們的views.Register會使用form.save()註冊及把用戶登入。 此外還會把一個叫title的parameter,傳到 sendmail function,作發送註冊確認email。 所以我們新建或修改views.pysendmail內容,變成這樣:
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把這頁美化一下。 */

Comments

There is no comment yet

New Comment

Please Login to comment