python3之Django表單(一)


1、HTML中的表單

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

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

大多數情況下被用到的表單標簽是輸入標簽(<input>),輸入類型是由類型屬性(type)定義的,大多數經常被用到的輸入類型下面做簡單介紹:

(1)文本域(Text Fields)

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

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

(2)密碼字段

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

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

(3)單選按鈕(Radio Buttons)

<input type="radio">標簽定義了表單單選框選項

<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通過加密的方式在后台提交

2、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

3、表單集

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>

4、從模型創建表單

 首先創建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()})

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM