前面學習的都只是如何顯示數據,但一直沒有關於如何響應用戶提交的數據。
表單,是在web中,用戶與服務器交互的重要途徑。
import django.forms
form django import forms
之間的區別是什麼?
form在Django中扮演的角色有:
*顯示form
*驗證用戶提交的數據
form的定義
~~~~~~~~~~
form的定義與model的定義很是類似:
____________________________________________
from django import forms
class BookForm(forms.Form):
isbn= forms.CharField(max_length=200)
title = forms.CharField(max_length=200)
--------------------------------------------
定義了一個BookForm表單,表單裏有isbn與title兩項。
BookForm能夠生成html表單文本,以下:
____________________________
book_form = BookForm()
html = book_form.as_table()
print(html)
----------------------------
執行打印出的結果是:
<tr><th><label for="id_isbn">Isbn:</label></th><td><input id="id_isbn" maxlength="50" name="isbn" type="text" /></td></tr>
<tr><th><label for="id_title">Title:</label></th><td><input id="id_title" maxlength="200" name="title" type="text" /></td></tr>
能夠看出,打印出來的文本沒有包含<form>與<input type="submit">,這些須要咱們
在模板中指定。Form只負責isbn與title的輸入,而不關心form的動做與提交方式。
因此,咱們最好用模板的方法先定義好一個模板,如book-form.html:
_______________________________
<form action="." method="get">
{{book_form}}
<br>
<input type="submit">
</form>
-------------------------------
在views.py中用render_to_response()生成HttpResponse:
____________________________________________________
def book_view(request):
book_form = BookForm()
response = render_to_response('book-form.html',
{'book_form':book_form.as_table()})
----------------------------------------------------
返回的頁面源碼:
<form action="." method="get">
<tr><th><label for="id_isbn">Isbn:</label></th><td><input id="id_isbn" maxlength="50" name="isbn" type="text" /></td></tr>
<tr><th><label for="id_title">Title:</label></th><td><input id="id_title" maxlength="200" name="title" type="text" /></td></tr>
<br>
<input type="submit">
</form>
Form除了as_table()方法,還有as_ul()與as_p()方法,默認是as_table()方法。
Form是在 django/forms/forms.py 定義的。
打開forms.py文件,能夠了解到,Form繼承於BaseForm。
BaseForm的定義大體以下:
___________________________________________________________________________
class BaseForm(object):
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, label_suffix=None):
...
def as_table(self):
...
def as_ul(self):
...
def as_p(self):
...
def __str__(self):
return self.as_table()
class Form(BaseForm):
...
---------------------------------------------------------------------------
auto_id爲<input id="id_xxx">,控件的自動id格式。爲''或None表示不須要id。
label_suffix爲lable名稱的後綴,默認爲":",能夠改。好比:label_suffix="="
prefix爲name的前綴,若是設置了prefix="aaa",那麼<input name="aaa-xxx">
initial爲初始值字典。
上面BookForm中只用到了一種域:CharField。除此以外還有不少種。
Fields定義在django/forms/fields.py文件裏。
打開fields.py文件,能夠看到除CharField外還有更多的Field供選擇:
Field
|--CharField
| |--RegexField
| |--EmailField
| |--URLField
| |--IPAddressField
| |--GenericIPAddressField
| `--SlugField
|--IntegerField
| |--FloatField
| `--DecimalField
|--BaseTomporalField
| |--DateField
| |--TimeField
| `--DateTimeField
|--FileField #file選擇文件
| `--ImageField
|--BooleanField #checkbox
| `--NullBooleanField #select:Unknow,Yes,No
|--ChoiceField #select
| |--TypedChoiceField
| |--FilePathField
| `--MultipleChoiceField
| `--TypedMultipleChoiceField
|--ComboField
`--MultiValueField
`--SplitDateTimeField
每種Field有個默認的Widget。
__________________________________
class Field(object):
widget = TextInput
...
class EmailField(CharField):
widget = EmailInput
...
class FileField(Field):
widget = ClearableFileInput
...
----------------------------------
Widget告訴Field生成哪一種web控件。
咱們也能夠爲Field指定Widget。
好比登錄表單:
_____________________________________________________________
class LoginForm(forms.Form):
#email = forms.EmailField()
email = forms.CharField(widget=widgets.EmailInput())
password = forms.CharField(widget=widgets.PasswordInput())
-------------------------------------------------------------
password這個域不能用明文顯示,因此更改了widget。
全部的Widget都定義在django/forms/widgets.py中。
有以下控件:
'Media', 'MediaDefiningClass', 'Widget', 'TextInput',
'EmailInput', 'URLInput', 'NumberInput', 'PasswordInput',
'HiddenInput', 'MultipleHiddenInput', 'ClearableFileInput',
'FileInput', 'DateInput', 'DateTimeInput', 'TimeInput', 'Textarea',
'CheckboxInput', 'SplitDateTimeWidget',
'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
'CheckboxSelectMultiple', 'MultiWidget',
基於模型的表單
~~~~~~~~~~~~~~
根據模型的定義來自動定義表單。以下:
______________________________________
from django import forms
from models import Book
class BookModelForm(froms.ModelForm):
class Meta:
model = Book
--------------------------------------
而Book的定義在models.py裏:
____________________________________________
class Book(models.Model):
isbn = models.CharField(max_length=50)
title = models.CharField(max_length=200)
author = models.ForeignKey('Author')
def __unicode__(self):
return self.title
--------------------------------------------
這樣以來,BookModelForm也有了與Book對應的isbn,title,author。
保存ModelForm
~~~~~~~~~~~~~
ModelForm與通常的Form的重要區別是,ModelForm具備save()功能。能將表單裏的數據
加入到數據庫,並返回一個Model對象。
爲了演示方便,我就不採用模板了。一樣是引用上面BookModelForm與Book:
_________________________________________________________________
def add_book_view(request):
book_form = forms.BookModelForm(request.GET)
try:
book_model = book_form.save()
content = '<p>Add ' + book_model.title + ' success!</p>'
except:
content = '<form action="." method="get">'
content += book_form.as_p()
content += '<input type="submit"></form>'
return HttpResponse(content)
-----------------------------------------------------------------
並將add_book_view視圖的url指定爲r'^add-book/'。
第一次訪問/add-book/時,因爲GET中沒有參數,因此在book_form.save()就會拋出異
常。在except中返回個表單給用戶。用戶填好後提交。此次再處理時,GET裏就有數據
了,因此book_form.save()正常,最後輸出success消息。
有時,咱們在save()時僅僅是想驗證一下用戶的輸入,並不打算提交到數據爲。
這裏,只要save(commit=False)便可。
如此,在save(commit=False)時返回了book模型的對象。咱們能夠繼而對其進一步修改
,再保存到數據庫。
_____________________________________________________
#book_model = book_form.save()
book_model = book_form.save(commit=False)
book_model.title = 'Balabala'
book_model.save()
-----------------------------------------------------
第一行只是驗證一下用戶的輸出是否是符合要求。而後對模型對象進行修改,最後才保
存到數據庫去。就這樣,在中間改了title,而後再保存到了數據庫。
ModelForm顯示個別域
~~~~~~~~~~~~~~~~~~~
ModelForm默認狀況下,與Model是一致的。可是不少時候,並非模型中全部的域都要
讓用戶填的。咱們能夠選擇性地選擇或排除個別域。
這裏就要用到Meta的exclude或fields。exclude表示排除什麼域,而fields表示須要顯
示哪些域。兩者不能同時使用。
_________________________________________________
class BookModelForm(forms.ModelForm):
class Meta:
model = Book
exclude = ('author') #表示不顯示author域
-------------------------------------------------
_________________________________________________
class BookModelForm(forms.ModelForm):
class Meta:
model = Book
fields = ('title', 'isbn')
#表示只顯示title與isbn域
-------------------------------------------------
重寫ModelForm中的域
~~~~~~~~~~~~~~~~~~~
_________________________________________
class BookModelForm(forms.ModelForm):
isbn = forms.CharField(max_length=13)
class Meta:
model = Book
-----------------------------------------
將Book中指定的CharField(max_length=50),改爲了13。
新增ModelForm中的域
~~~~~~~~~~~~~~~~~~~
______________________________________
class BookModelForm(forms.ModelForm):
review = forms.CharField()
class Meta:
model = Book
--------------------------------------
這樣以來,BookModelForm不只只有Book中的域,還有review。
表單的驗證
~~~~~~~~~~
Form的is_valid()文件能夠用來驗證數據是否合法。
若是數據合法,Form對象則會有cleaned_data屬性。若是不合法,則是errors。
__________________________________________________________________
def add_author_view(request):
content = None
if request.GET: # 檢查GET是否有表單數據
author_form = forms.AuthorModelForm(request.GET)
if author_form.is_valid(): # 檢查數據是否合法
print(author_form.cleaned_data)
try:
author_form.save()
content = '<p>Success</p>'
except:
content = '<p>Something wrong while saving.</p>'
else:
content = str(author_form.errors) # 用errors返回錯誤信息
else:
content = '<form action=".">'
content += forms.AuthorModelForm().as_p()
content += '<input type="submit"></form>'
return HttpResponse(content)
------------------------------------------------------------------
上面用到了author_form.is_valid()進行數據合法性驗證。
若是成功,則會有author_form.cleaned_data,若是失敗會有author_form.errors。
這兩則只會存在一個,不會同時存在。
html