python3之Django表單(一)

一、HTML中的表單

在HTML種,表單是在<form>...</form>種的元素,它容許用戶輸入文本,選擇選項,操做對象等,而後發送這些數據到服務器html

表單元素容許用戶在表單種輸入內容如,文本域(textarea)、下拉列表、單選框(radio-buttons)、複選框(checkboxes)等。web

大多數狀況下被用到的表單標籤是輸入標籤(<input>),輸入類型是由類型屬性(type)定義的,大多數常常被用到的輸入類型下面作簡單介紹:數據庫

(1)文本域(Text Fields)django

文本域經過<input type="text">標籤來設定,當用戶要在表單種輸入字母,數字等內容是,就會用到文本域,在大多數瀏覽器種,文本域的缺省寬度是20個字符:瀏覽器

<form>
    姓名:<input type="text" name="username"><br>
</form>

(2)密碼字段服務器

密碼字段經過標籤<input type="password">來定義,密碼字段字符不會明文顯示,而是以星號或圓點替代:app

<form>
    姓名:<input type="text" name="username"><br>
    密碼:<input type="password" name="password">
</form>

(3)單選按鈕(Radio Buttons)函數

<input type="radio">標籤訂義了表單單選框選項post

<form>
    姓名:<input type="text" name="username"><br>
    密碼:<input type="password" name="password"><br>
    性別:<input type="radio" name="sex" value="man"><input type="radio" name="sex" value="weman"><br>

</form>

(4)複選框(Checkboxes)學習

<input type="checkbox"定義了複選框,用戶能夠從若干個給定的選擇種選擇多個

<form>
    姓名:<input type="text" name="username"><br>
    密碼:<input type="password" name="password"><br>
    性別:<input type="radio" name="sex" value="man"><input type="radio" name="sex" value="weman"><br>
    愛好:<input type="checkbox" name="vehicle" value="yundong">運動
          <input type="checkbox" name="vehicle" value="youxi">遊戲
          <input type="checkbox" name="vehicle" value="xuexi">學習

</form>

(5)提交按鈕(Submit Button)

<input type="submit">定義了提交按鈕,當用戶單擊確認按鈕時,表單的內容就會被傳送到動做屬性定義的目的文件中

<form action="index.html" method="post">
    姓名:<input type="text" name="username"><br>
    密碼:<input type="password" name="password"><br>
    性別:<input type="radio" name="sex" value="man"><input type="radio" name="sex" value="weman"><br>
    愛好:<input type="checkbox" name="vehicle" value="yundong">運動
          <input type="checkbox" name="vehicle" value="youxi">遊戲
          <input type="checkbox" name="vehicle" value="xuexi">學習<br>
    <input type="submit" value="提交">
</form>

瀏覽器表單中的數據會發往action屬性指定的URL,而且使用它的method屬性指定的HTTP方法post,當點擊submit類型的提交時,會將數據發送到index.html中。

HTML5有許多新的input類型:

color類型選取顏色,date類型日期選擇器,datetime-local類型選擇一個日期和時間,email類型用於e-mail地址的輸入域,month類型容許選擇一個月份,number類型用於數值的輸入域,rang類型定義必定範圍內數字的輸入域,顯示爲滑動條可設置最大值max和最小值min,search類型用於搜索域,tel類型定義電話號碼字段,time類型定義一個時間選擇,url類型用於URL地址的輸入域,week類型容許選擇周和年。

處理表單時只會用到GET和POST兩種HTTP方法,GET方法會將提交的數據捆綁到URL中,而POST經過加密的方式在後臺提交

二、Django中的表單

Django會處理涉及表單的三個部分:

準備並重組數據,以便下一步的渲染;爲數據建立HTML表單;接收並處理客戶端提交的表單以及數據。

Django表單系統的核心組件是Form類,Form類描述一張表單並決定它如何工做並呈現

Form類,相似於模型類的字段映射到數據庫字段的方式,表單類的字段會映射到HTML表單的<input>元素,表單字段自己也是類,它們管理表單數據並提交表單執行驗證,在瀏覽器中表單字段以HTML控件的形式展示給咱們,在Django中每一個字段類型都有與之匹配的控件類,在必要時也能夠覆蓋

在Django中渲染一個對象的過程一般爲:在視圖中獲取數據,而後將數據傳遞給模板,使用模板變量將數據擴展到HTML標記,下面咱們在Django中構建表單

 在app中新建forms.py文件:

from django import forms

#首先它繼承Form類,而後經過控件類CharField定義文本域並指定屬性
class IndexForm(forms.Form):
    username = forms.CharField(label='姓名',max_length=100)

而後在編輯視圖並引入表單類:

#views.py

from django.shortcuts import render
from django.http import HttpResponse
from .forms import IndexForm

#新建視圖函數處理表單,首先判斷提交類型爲post則經過表單類接收POST請求數據並填充表單類,而後判斷數據是否有效並提交到後臺,此處作演示只作判斷並提示接收成功,
#若是提交類型不爲POST則建立空表單經過變量傳遞給模板
def get_name(request): if request.method == 'POST': form = IndexForm(request.POST) print(form) if form.is_valid(): return HttpResponse('提交到後臺成功!') else: form = IndexForm() return render(request,'index.html',{'form':form})

表單類生成的數據以下:

<tr><th><label for="id_username">姓名:</label></th><td><input type="text" name="username" value="root" maxlength="100" required id="id_username"></td></tr>

在模板中只需簡單的配置form標籤並接收變量,注意表單不包含提交標籤須要在模板中本身建立

<form action="{% url 'formtest' %}" method="post">
    {% csrf_token %}  #此處爲跨站請求僞造保護功能django自提供
    {{ form }}
    <input type="submit" value="提交">
</form>

頁面程序效果:

<form action="/" method="post">
    <input type="hidden" name="csrfmiddlewaretoken" value="e9Je91NyzZFWx83yXQbSiHYYjH3g4tsiz22zAjEAhSfKnNzPjAINCVd1iHZAnC4B">
    <label for="id_username">姓名:</label><input type="text" name="username" maxlength="100" required="" id="id_username">
    <input type="submit" value="提交">
</form>

在模板中咱們只需將表單在上下問中進行渲染,來獲得對應的標籤元素,如上面的form變量渲染{{ form }}

但在表單渲染選項還可使用其餘渲染方式:

{{ form.as_table }}包裝在<tr>標記中的表格單元格顯示數據,但必須本身提供外層<table>元素

{{ form.as_p }}包裹在<p>標記中的顯示數據

{{ form.as_ul }}包裹在<li>標記中顯示數據,但必須本身提供外層<ul>元素

手動渲染字段:

 循環遍歷每一個字段對字段屬性手動渲染,以下field.errors輸出包含改字段驗證的錯誤信息,field.label_tag爲帶<label>標籤的label值

#遍歷表單字段
<form action="{% url 'index' %}" method="post">
    {% csrf_token %}
    {% for field in form %}
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}<br>
    {% endfor %}
    <input type="submit" value="提交">
</form>


#渲染效果
<form action="/" method="post">
    <input type="hidden" name="csrfmiddlewaretoken" value="benu1PCIYH6XKtSxa7cQyR8wwwIYvae7w7GPs7tKGAGLA8oOwRJLS5nzvwEiOjQq">
        <label for="id_subject">Subject:</label> <input type="text" name="subject" maxlength="100" required="" id="id_subject"><br>
        <label for="id_message">Message:</label> <textarea name="message" cols="40" rows="10" required="" id="id_message"></textarea><br>
        <label for="id_sender">Sender:</label> <input type="email" name="sender" required="" id="id_sender"><br>
        <label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"><br>
    <input type="submit" value="提交">
</form>

field.label_tag:輸出field的label元素,如:<label for="id_subject">Subject:</label>

field:輸出field的input,如:<input type="text" name="subject" maxlength="100" required="" id="id_subject">

field.errors:輸出field的errors元素,通常在form表單驗證出錯時顯示

field.id_for_label:輸出字段的ID值

field.value:輸出字段填充的值

field.html_name:輸出字段的名稱

field.help_text:輸出與該字段的幫助文本

field.is_hidden:若是是隱藏字段屬性值爲True不然爲False

三、表單集

Formset表單集是多個表單的集合,Formset在web開發中應用很廣泛,它可讓用戶在同一個頁面提交多張表單,一鍵添加多個數據

Django針對不一樣的formset提供了三種方法:formet_factory,modelformset_factory和inlineformset_factory

(1)使用formset_factory

對應繼承forms.Form的自定義表單,咱們可使用formset_factory,經過設置extra指定表單數量,max_num指定表單數量最大值

首先建立表單並使用formset_factory方法指定建立表單集並指定表單數量

#forms.py

from django import forms
from django.forms import formset_factory

class registerForm(forms.Form):
    username = forms.CharField(max_length=120)
    age = forms.IntegerField()
    pub_date = forms.DateField(required=False)

registerFormset = formset_factory(registerForm,extra=3,max_num=5)

在視圖views.py裏使用formset

#views.py

from django.shortcuts import render,HttpResponse
from .forms import registerFormset

def register(request):
    if request.method == 'POST':
        formset = registerFormset(request.POST,request.FILES)
        if formset.is_valid():
            return HttpResponse('formset is ok')
    else:
        formset = registerFormset()
    return render(request,'register.html',context={'formset':formset})

最後在模版中應用表單便可

<form action="{% url 'register' %}" method="post">
    {{ formset.management_form }}
    {% for form in formset %}
    {{ form.as_p }}
    {% endfor %}
</form>

四、從模型建立表單

 首先建立model模型:

from django.db import models
from django.utils import timezone

TITLE_CHOICES = (
    ('MR','Mr.'),
    ('MRS','Mrs.'),
    ('MS','Ms.'),
)

class Author(models.Model):
    name = models.CharField(max_length=100,verbose_name='姓名')
    title = models.CharField(max_length=3,choices=TITLE_CHOICES,verbose_name='標題')
    birth_date = models.DateField(default=timezone.now,blank=True,null=True,verbose_name="建立時間")

    def __str__(self):
        return self.name

根據模型建立表單文件:

#forms.py
#導入模型表單類
from django.forms import ModelForm
from .models import Author

#繼承模型表單類建立表單
class AuthorForm(ModelForm):
    class Meta:
        model = Author    #指定model
        fields = ['name','title','birth_date']  #指定要顯示的字段,全顯示可以使用"__all__"

在經過模型建立表單時,咱們只需繼承Django的模型表單類,而後重寫它的屬性便可,model指定要建立表單的模型,fields指定顯示的模型字段,全顯示能夠用「__all__"代替,還有其餘的類屬性exclude指定排除的字段,labels指定提示信息,help_texts指定幫助提示信息,widgets指定自定義插件,error_messages自定義錯誤信息,field_classes自定義字段類,localized_fields本地化時區時間,根據setting中TIME_ZONE設置的不一樣時區顯示時間

from django import forms
from django.forms import ModelForm
from .models import Author

class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ['name','title','birth_date']
        widgets = {
            'title':forms.Textarea(attrs={'cols':80,'rows':20})
        } #覆蓋重寫title字段的類型
        labels = {
            'name':'做者',
            'title':'頭銜',
            'birth_date':'出生日期',
        }
        error_messages = {
            'name':{
                'max_length':'名字長度在15個字符內',
            }
        }

在django中的模型字段和表單字段的字段類型定義都差很少,比較特殊的是ForeignKey和ManyToManyField模型字段在表單中的字段類型會有所不一樣:

ForeignKey由django.forms.ModelChoiceField表示,它是一個ChoiceField,其選項是一個模型QuerySet

ManyToManyField由django.forms.ModelMultipleChoiceField表示,它是一個MultipleChoiceField,其選項爲一個模型QuerySet

另外,每一個生成的表單字段的屬性設置以下:

若是模型字段設置了blank=True,那麼表單字段的required屬性被設置爲False,否知爲True

表單字段的label設置爲模型字段的verbose_name,而且首字母大寫

表單字段的help_text設置爲模型字段的help_text

若是模型字段設置了choices,那麼表單字段的widget會被設置爲select,其選項來自模型字段的choices,這些選項一般包含一個默認選中的空選項,若是字段設置了必填,則會強制用戶進行選項,若是模型字段設置了blank=False以及一個明確的default值,則表單字段中不會包含空選項

在視圖中使用表單:

#views.py

from django.shortcuts import render,HttpResponse
from .forms import AuthorForm
from .models import Author

def test(request):
    if request.method == 'POST':
        author_form = AuthorForm(request.POST)
        if author_form.is_valid():
            author_form.save(commit=True)
            return HttpResponse('提交成功')
    else:
        author_form = AuthorForm()
    obj = Author.objects.all()
    return render(request,'test.html',{"author_form":author_form,'obj':obj})

views.py中使用ModelForm的save()方法將表單數據保存到數據庫中,參數commit爲True時寫如數據庫,若是爲False則建立一個Model對象但不保存到數據庫中,若是要更新某個對象可使用save的instance參數來指定要更新的model對象

在模板中提交併展現數據:

#test.html

<body>
<h2>Author Form:</h2>
<form action="{% url 'test' %}" method="post">
    {% csrf_token %}
    {{ author_form }}
    <input type="submit" value="提交">
</form>
<h2>Author Form output:</h2>
<ul>
    {% for i in obj %}
    <li>{{ i.id }}:{{ i.name }}:{{ i.title }}:{{ i.birth_date }}</li>
    {% endfor %}
</ul>
</body>

表單模板ModelForm中有一個工廠函數能夠直接經過Model建立表單modelform_factory(),在不須要不少自定義的狀況下是很方便的

from .models import Author
from django import forms
from django.forms.models import modelformset_factory

modelform_Author = modelformset_factory(model=Author,fields=('__all__'),widgets={'title':forms.Textarea()})
相關文章
相關標籤/搜索