Django學習筆記之——Forms


前面學習的都只是如何顯示數據,但一直沒有關於如何響應用戶提交的數據。
表單,是在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

相關文章
相關標籤/搜索