表單模型(一)
Django的Form表單類與Django模型描述對象的邏輯結構、行為以及它呈現給我們内容的形式的方式大緻相同
假設你想從表單接收使用者名資料,一般情況下,你需要在HTML中手動編寫一個如下的表單元素:
<form action="/student/" method="post">
<label for="name">姓名: </label>
<input id="name" type="text" name="name" value="{{ name }}">
<input type="submit" value="送出">
</form>
1. 編寫表單類
我們可以通過Django提供的Form類來生成上面的表單,不再需要手動在HTML中編寫
首先,在你目前app内建立一個
forms.py
檔案,然後輸入下面的内容:
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(label='name', max_length=100)
- 所有的表單類都要繼承forms.Form類
-
限制最大長度為100。它同時起到兩個作用,一是在浏覽器頁面限制使用者輸入不可超過100個字元,二是在後端伺服器驗證使用者輸入的長度不可超過100max_length
每個Django表單的執行個體都有一個内置的
is_valid()
方法,用來驗證接收的資料是否合法。如果所有資料都合法,那麼該方法将傳回True,并将所有的表單資料轉存到它的一個叫做
cleaned_data
的屬性中,該屬性是一個字典類型資料。
當我們将上面的表單渲染成真正的HTML元素,其内容如下:
<label for="name">name: </label>
<input id="name" type="text" name="name" maxlength="100" required />
一定要注意,它不包含
<form>
标簽本身以及送出按鈕!!!為什麼要這樣?友善你自己控制表單動作和CSS,JS以及其它類似bootstrap架構的嵌入!
2. 視圖處理
需要在視圖中,執行個體化我們編寫好的表單類
# views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import NameForm
def get_name(request):
# 如果form通過POST方法發送資料
if request.method == 'POST':
# 接受request.POST參數,綁定要驗證的資料
form = NameForm(request.POST)
# 驗證資料是否合法
if form.is_valid():
# 處理form.cleaned_data中的資料
return HttpResponse('hello world
# 如果是通過GET方法請求資料,傳回一個空的表單
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
- 對于GET方法請求頁面時,傳回空的表單,讓使用者可以填入資料
- 對于POST方法,接收表單資料,并驗證
可以通過表單的
is_bound
屬性可以獲知一個表單已經綁定了資料,還是一個空表
3. 模闆處理
在Django的模闆中,我們隻需要按下面處理,就可以得到完整的HTML頁面,但是
submit
按鈕需要自己定義:
<form action="/student/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="送出" />
</form>
- 使用POST的方法時,必須添加
标簽,用于處理csrf安全機制{% csrf_token %}
-
Django會為你生成其它所有的form标簽元素{{ form }}
- 送出按鈕需要手動添加!
4. 表單字段
上面的例子中,隻有一個使用者名輸入框,太簡單了,實際上有更多的表單元素。看下面的例子:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField(widget=forms.Textarea)
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)
這個例子就有4個框組了。實際上Django的表單子產品為我們内置了許多表單字段,如下所示:
- BooleanField
- CharField
- ChoiceField
- TypedChoiceField
- DateField
- DateTimeField
- DecimalField
- DurationField
- EmailField
- FileField
- FilePathField
- FloatField
- ImageField
- IntegerField
- JSONField
- GenericIPAddressField
- MultipleChoiceField
- TypedMultipleChoiceField
- NullBooleanField
- RegexField
- SlugField
- TimeField
- URLField
- UUIDField
- ComboField
- MultiValueField
- SplitDateTimeField
- ModelChoiceField
- ModelMultipleChoiceField
每一個表單字段類型都對應一種Widget類,每一種Widget類都對應了HMTL語言中的一種input元素類型,比如
<input type="text">
。需要在HTML中實際使用什麼類型的input,就需要在Django的表單字段中選擇相應的field。比如要一個
<input type="text">
,可以選擇一個
CharField
。
一旦你的表單接收資料并驗證通過了(
is_valid()
),那麼就可以從
form.cleaned_data
字典中讀取所有的表單資料,并且已經轉化為恰當的Python類型。例子:
# views.py
from django.core.mail import send_mail
if form.is_valid():
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
cc_myself = form.cleaned_data['cc_myself']
recipients = ['[email protected]']
if cc_myself:
recipients.append(sender)
send_mail(subject, message, sender, recipients)
return HttpResponseRedirect('/thanks/')
5. 使用表單模闆
① 表單渲染格式
前面我們通過
{{ form }}
模闆語言,簡單地将表單渲染到HTML頁面中了,實際上,有更多的方式:
-
将表單渲染成一個表格元素,每個輸入框作為一個{{ form.as_table }}
标簽<tr>
-
将表單的每個輸入框包裹在一個{{ form.as_p }}
标簽内 tags<p>
-
将表單渲染成一個清單元素,每個輸入框作為一個{{ form.as_ul }}
标簽<li>
注意:你要自己手動編寫
<table>
和
<ul>
标簽。
下面是将上面的ContactForm作為
{{ form.as_p }}
的渲染出的html:
<p><label for="id_subject">Subject:</label>
<input id="id_subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="id_message">Message:</label>
<textarea name="message" id="id_message" required></textarea></p>
<p><label for="id_sender">Sender:</label>
<input type="email" name="sender" id="id_sender" required></p>
<p><label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself"></p>
注意:Django自動為每個input元素設定了一個id名稱,對應label的for參數。
② 手動渲染表單字段
直接
{{ form }}
雖然好,啥都不用操心,但是往往并不是你想要的,比如你要使用CSS和JS,比如你要引入Bootstarps架構,這些都需要對表單内的input元素進行額外控制,那怎麼辦呢?手動渲染字段就可以了。
可以通過
{{ form.name_of_field }}
擷取每一個字段,然後分别渲染,如下例所示:
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="{{ form.message.id_for_label }}">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="{{ form.sender.id_for_label }}">Your email address:</label>
{{ form.sender }}
</div>
<div class="fieldWrapper">
{{ form.cc_myself.errors }}
<label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
{{ form.cc_myself }}
</div>
其中的label标簽甚至可以用
label_tag()
方法來生成,于是可以簡寫成下面的樣子:
<div class="fieldWrapper">
{{ form.subject.errors }}
{{ form.subject.label_tag }}
{{ form.subject }}
</div>
③ 渲染表單錯誤資訊
注意上面的例子中,我們使用
{{ form.name_of_field.errors }}
模闆文法,在表單裡處理錯誤資訊。對于每一個表單字段的錯誤,它其實會實際生成一個無序清單,參考下面的樣子:
<ul class="errorlist">
<li>Sender is required.</li>
</ul>
這個清單有個預設的CSS樣式類
errorlist
,如果你想進一步定制這個樣式,可以循環錯誤清單裡的内容,然後單獨設定樣式:
{% if form.subject.errors %}
<ol>
{% for error in form.subject.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
一切非字段的錯誤資訊,比如表單的錯誤,隐藏字段的錯誤都儲存在
{{ form.non_field_errors }}
中,上面的例子,我們把它放在了表單的外圍上面,它将被按下面的HTML和CSS格式渲染:
<ul class="errorlist nonfield">
<li>Generic validation error</li>
</ul>
④ 循環表單的字段
如果你的表單字段有相同格式的HTML表現,那麼完全可以循環生成,不必要手動的編寫每個字段,隻需要使用模闆語言中的
{% for %}
循環,減少備援和重複代碼,如下所示:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
下表是
{{ field }}
中非常有用的屬性,這些都是Django内置的模闆語言給我們提供的友善:
屬性 | 說明 |
---|---|
| 字段對應的label資訊 |
| 自動生成字段的label标簽 |
| 自定義字段标簽的id |
| 目前字段的值,比如一個Email字段的值 |
| 指定字段生成的input标簽中name屬性的值 |
| 字段的幫助資訊 |
| 包含錯誤資訊的元素 |
| 用于判斷目前字段是否為隐藏的字段,如果是,傳回True |
| 傳回字段的參數清單。例如 |
⑤ 不可見字段
很多時候,我們的表單中會有一些隐藏的不可見的字段,我們需要讓它在任何時候都仿佛不存在一般,比如有錯誤的時候,如果你在頁面上顯示了不可見字段的錯誤資訊,那麼使用者會很迷惑,這是哪來的呢?是以,通常我們是不顯示不可見字段的錯誤資訊的。
Django提供了兩種獨立的方法,用于循環那些不可見的和可見的字段,
hidden_fields()
和
visible_fields()
。這裡,我們可以稍微修改一下前面的例子:
{# 循環那些不可見的字段 #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{# 循環可見的字段 #}
{% for field in form.visible_fields %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
⑥ 重用表單模闆
如果你在自己的HTML檔案中,多次使用同一種表單模闆,那麼你完全可以把表單模闆存成一個獨立的HTML檔案,然後在别的HTML檔案中通過include模闆文法将其包含進來,如下例所示:
# 實際的頁面檔案中:
{% include "form_snippet.html" %}
-----------------------------------------------------
# 單獨的表單模闆檔案form_snippet.html:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
如果你的頁面同時引用了好幾個不同的表單模闆,那麼為了防止沖突,你可以使用with參數,給每個表單模闆取個别名,如下所示:
{% include "form_snippet.html" with form=comment_form %}
在使用的時候就是:
{% for field in comment_form %}
......