Django實戰(一)-----用戶登錄與註冊系統4(表單)
我們前面都是手工在HTML文件中編寫表單form元素,然後在views.py的視圖函數中接收表單中的用戶數據,再編寫驗證代碼進行驗證,最後使用ORM進行數據庫的增刪改查。這樣費時費力,整個過程比較復雜,而且有可能寫得不太恰當,數據驗證也比較麻煩。
設想一下,如果我們的表單擁有幾十上百個數據字段,有不同的數據特點,如果也使用手工的方式,其效率和正確性都將無法得到保障。
有鑒於此,Django在內部集成了一個表單功能,以面向對象的方式,直接使用Python代碼生成HTML表單代碼,專門幫助我們快速處理表單相關的內容。
Django的表單給我們提供了下面三個主要功能:
- 準備和重構數據用於頁面渲染;
- 為數據創建HTML表單元素;
- 接收和處理用戶從表單發送過來的數據。
編寫Django的form表單,非常類似我們在模型系統裏編寫一個模型。
在模型中,一個字段代表數據表的一列,而form表單中的一個字段代表<form>
中的一個<input>
元素。
一、創建表單模型
在項目根目錄的login文件夾下,新建一個forms.py
文件,也就是/login/forms.py
,又是我們熟悉的Django組織文件的套路,一個app一套班子!
在/login/forms.py
中寫入下面的代碼,是不是有一種編寫數據model模型的既視感?
from django import forms class UserForm(forms.Form): username = forms.CharField(label="用戶名", max_length=128) password = forms.CharField(label="密碼", max_length=256, widget=forms.PasswordInput)
說明:
- 要先導入forms模塊
- 所有的表單類都要繼承forms.Form類
- 每個表單字段都有自己的字段類型比如CharField,它們分別對應一種HTML語言中
<form>
內的一個input元素。這一點和Django模型系統的設計非常相似。 - label參數用於設置
<label>
標簽 max_length
限制字段輸入的最大長度。它同時起到兩個作用,一是在瀏覽器頁面限制用戶輸入不可超過字符數,二是在後端服務器驗證用戶輸入的長度也不可超過。widget=forms.PasswordInput
用於指定該字段在form表單裏表現為<input type=‘password‘ />
二、修改視圖
使用了Django的表單後,就要在視圖中進行相應的修改:
from django.shortcuts import render from django.shortcuts import redirect from . import models from django import forms from login import forms def index(request): pass return render(request, ‘login/index.html‘) def login(request): if request.method == "POST": login_form = forms.UserForm(request.POST) message = "請檢查填寫的內容!" if login_form.is_valid(): username = login_form.cleaned_data[‘username‘] password = login_form.cleaned_data[‘password‘] try: user = models.User.objects.get(name=username) if user.password == password: return redirect(‘/index/‘) else: message = "密碼不正確!" except: message = "用戶不存在!" return render(request, ‘login/login.html‘, locals()) login_form = forms.UserForm() return render(request, ‘login/login.html‘, locals()) def register(request): pass return render(request, ‘login/register.html‘) def logout(request): pass return redirect("/index/")
說明:
- 對於非POST方法發送數據時,比如GET方法請求頁面,返回空的表單,讓用戶可以填入數據;
- 對於POST方法,接收表單數據,並驗證;
- 使用表單類自帶的
is_valid()
方法一步完成數據驗證工作; - 驗證成功後可以從表單對象的
cleaned_data
數據字典中獲取表單的具體值; - 如果驗證不通過,則返回一個包含先前數據的表單給前端頁面,方便用戶修改。也就是說,它會幫你保留先前填寫的數據內容,而不是返回一個空表!
另外,這裏使用了一個小技巧,Python內置了一個locals()函數,它返回當前所有的本地變量字典,我們可以偷懶的將這作為render函數的數據字典參數值,就不用費勁去構造一個形如{‘message‘:message, ‘login_form‘:login_form}
的字典了。這樣做的好處當然是大大方便了我們,但是同時也可能往模板傳入了一些多余的變量數據,造成數據冗余降低效率。
三、 修改login頁面
Django的表單很重要的一個功能就是自動生成HTML的form表單內容。現在,我們需要修改一下原來的login.html
文件:
{% extends ‘login/base.html‘ %} {% load staticfiles %} {% block title %}登錄{% endblock %} {% block css %}<link href="{% static ‘css/login.css‘ %}" rel="stylesheet"/>{% endblock %} {% block content %} <div class="container"> <div class="col-md-4 col-md-offset-4"> <form class=‘form-login‘ action="/login/" method="post"> {% if message %} <div class="alert alert-warning">{{ message }}</div> {% endif %} {% csrf_token %} <h2 class="text-center">歡迎登錄</h2> {{ login_form }} <button type="reset" class="btn btn-default pull-left">重置</button> <button type="submit" class="btn btn-primary pull-right">提交</button> </form> </div> </div> <!-- /container --> {% endblock %}
說明:
- 你沒有看錯!一個
{{ login_form }}
就直接完成了表單內容的生成工作!login_form
這個名稱來自你在視圖函數中生成的form實例的變量名! - 但是,它不會生成
<form>...</form>
標簽,這個要自己寫; - 使用POST的方法時,必須添加
{% csrf_token %}
標簽,用於處理csrf安全機制; - Django自動為每個input元素設置了一個id名稱,對應label的for參數
- 重置和提交按鈕需要自己寫,Django不會幫你生成!
我們到瀏覽器中,看下實際生成的html源碼是什麽:
<form class=‘form-login‘ action="/login/" method="post"> <div class="alert alert-warning">密碼不正確!</div> <input type=‘hidden‘ name=‘csrfmiddlewaretoken‘ value=‘t7MdqJzR7fbiDth5ZQSBpHb22F8sUkjTy32MlEuhXdW8EZPTwcTNuF0PPOHlxKPz‘ /> <h2 class="text-center">歡迎登錄</h2> <tr><th><label for="id_username">用戶名:</label></th><td><input type="text" name="username" value="jack" maxlength="128" required id="id_username" /></td></tr> <tr><th><label for="id_password">密碼:</label></th><td><input type="password" name="password" maxlength="256" required id="id_password" /></td></tr> <button type="reset" class="btn btn-default pull-left">重置</button> <button type="submit" class="btn btn-primary pull-right">提交</button> </form>
也就是說,Django的form表單功能,幫你自動生成了下面部分的代碼:
<tr><th><label for="id_username">用戶名:</label></th><td><input type="text" name="username" value="jack" maxlength="128" required id="id_username" /></td></tr> <tr><th><label for="id_password">密碼:</label></th><td><input type="password" name="password" maxlength="256" required id="id_password" /></td></tr>
這看起來好像一個<table>
標簽啊?沒錯,就是<table>
標簽,而且是不帶<table></table>
的,捂臉!
實際上除了通過{{ login_form }}
簡單地將表單渲染到HTML頁面中了,還有下面幾種方式:
{{ login_form.as_table }}
將表單渲染成一個表格元素,每個輸入框作為一個<tr>
標簽{{ login_form.as_p }}
將表單的每個輸入框包裹在一個<p>
標簽內{{ login_form.as_ul }}
將表單渲染成一個列表元素,每個輸入框作為一個<li>
標簽
註意:上面的渲染方法中都要自己手動編寫<table>
或者<ul>
標簽。
重新啟動服務器,刷新頁面,如下圖所示:
四、手動渲染表單字段
直接{{ login_form }}
雖然好,啥都不用操心,但是界面真的很醜,往往並不是你想要的,如果你要使用CSS和JS,比如你要引入Bootstarps框架,這些都需要對表單內的input元素進行額外控制,那怎麽辦呢?手動渲染字段就可以了。
可以通過{{ login_form.name_of_field }}
獲取每一個字段,然後分別渲染,如下例所示:
<div class="form-group"> {{ login_form.username.label_tag }} {{ login_form.username}} </div> <div class="form-group"> {{ login_form.password.label_tag }} {{ login_form.password }} </div>
其中的label標簽可以用label_tag
方法來生成。這樣子更加靈活了,但是靈活的代價就是我們要寫更多的代碼,又偏向原生的HTML代碼多了一點。
但是問題又...又...又來了!刷新登錄頁面,卻是下圖的樣子:
好像Bootstrap沒有生效呀!仔細查看最終生成的頁面源碼,你會發現,input元素裏少了一個CSS的類form-control
。這可咋辦?
在form類裏添加attr屬性即可,如下所示修改login/forms.py
from django import forms class UserForm(forms.Form): username = forms.CharField(label="用戶名", max_length=128, widget=forms.TextInput(attrs={‘class‘: ‘form-control‘})) password = forms.CharField(label="密碼", max_length=256, widget=forms.PasswordInput(attrs={‘class‘: ‘form-control‘}))
再次刷新頁面,我們熟悉的Bootstarp框架UI又回來了!
實際上,Django針對{{ login_form }}
表單,提供了很多靈活的模板語法,可以循環,可以取值,可以針對可見和不可見的部分單獨控制,詳細內容可以參考教程前面的章節。
Django實戰(一)-----用戶登錄與註冊系統4(表單)