django之Form表單

HTML表單

在HTML中,表單是<form>...</form> 之間元素的集合,它們容許訪問者輸入文本、選擇選項、操做對象和控制等等,而後將信息發送回服務器。html

某些表單的元素 —— 文本輸入和複選框 —— 很是簡單並且內建於HTML 自己。其它的表單會複雜些;例如彈出一個日期選擇對話框的界面、容許你移動滾動條的界面、使用JavaScript 和CSS 以及HTML 表單<input> 元素來實現操做控制的界面。與<input> 元素同樣,一個表單必須指定兩樣東西:前端

  1. 目的地:響應用戶輸入數據的URL
  2. 方式:發送數據所使用的HTTP 方法

例如,Django Admin 站點的登陸表單包含幾個<input> 元素:type="text" 用於用戶名,type="password" 用於密碼,type="submit" 用於「Log in" 按鈕。它還包含一些用戶看不到的隱藏的文本字段,Django 使用它們來決定下一步的行爲。python

它還告訴瀏覽器表單數據應該發往<form> 的action 屬性指定的URL —— /admin/,並且應該使用method 屬性指定的HTTP 方法 —— post。git

當觸發<input type="submit" value="Log in"> 元素時,數據將發送給/admin/。正則表達式

Django 中的表單

Django 的Form 類

表單系統的核心部分是Django 的Form 類。Django 的模型描述一個對象的邏輯結構、行爲以及展示給咱們的方式,與此相似,Form 類描述一個表單並決定它如何工做和展示。數據庫

就像模型類的屬性映射到數據庫的字段同樣,表單類的字段會映射到HTML 的<input>表單的元素。django

表單字段在瀏覽器中呈現給用戶的是一個HTML 的「widget」 —— 用戶界面的一個片斷。每一個字段類型都有一個合適的默認Widget 類,須要時能夠覆蓋。api

 

widget 部件瀏覽器

實例化、處理和渲染表單

在Django 中渲染一個對象時,咱們一般:服務器

  1. 在視圖中得到它(例如,從數據庫中獲取)
  2. 將它傳遞給模板上下文
  3. 使用模板變量將它擴展爲HTML 標記

在模板中渲染表單和渲染其它類型的對象幾乎同樣,除了幾個關鍵的差異。

 

構建一個表單

在html裏構建這裏就不寫了

1.在app下面新建一個存放Forn類的文件

例如:myforms.py

  

#!/usr/bin/env python
#-*- coding:utf-8 -*-
from django import forms
from django.forms import  fields
class UserForm(forms.Form):
    user = fields.CharField(
        max_length=18,
        min_length=6,
        required = True,
        error_messages={
            'required':'用戶輸入爲空',
            'max_length':'用戶輸入太長了',
             'min_length':'用戶輸入過短了'
        })    #自定義錯誤顯示信息
    pwd = fields.CharField(required=True,min_length=8)
    age = fields.IntegerField(required=True)
    email = fields.EmailField(required=True,min_length=8,
                              error_messages={
                                  'invalid':"用戶輸入格式錯誤,只要是格式錯誤都用invalid"
                              })

  

  

注:它不包含 <form> 標籤和提交按鈕。咱們必須本身在模板中提供它們。

要操做一個經過URL發佈的表單,咱們要在視圖中實例表單。

2.views.py

from django.shortcuts import render
from django.shortcuts import redirect
from app01.myfoms import UserForm
# Create your views here.

def users(request):
    if request.method == "GET":
        obj = UserForm()  #這就至關於自動生成了一個html
        return render(request,'fm.html',{'obj':obj})

    elif request.method == 'POST':
        fo = UserForm(request.POST)
        # print(fo)  #前端提交過來的數據
        v = fo.is_valid()  # 判斷髮過來的數據驗證是否經過
        if v:

            print(fo.cleaned_data)  # 查看用戶提交的數據
            return redirect('http://www.baidu.com')  # 成功驗證跳轉到百度
        else:
            print(fo.errors)  # 查看相應提交數據的錯誤信息
            return render(request, 'fm.html', {"obj": fo})
    return render(request, 'fm.html')

  

3.url

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^users/$', views.users),

]

  

4.模板html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/users/" method="POST" novalidate>
    <p>{{ obj.user }}{{ obj.errors.user.0 }} </p>
    <p>{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
    <p>{{ obj.age }}{{ obj.errors.age.0 }}</p>
    <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
    <input type="submit" value="提交">
</form>

/* obj.error.user.0 是顯示在輸入框後顯示錯誤的顯示信息  */

</body>
</html>

  

提示:

form類實例化的方法和屬性
is_valid() 方法     判斷表單提交是否合法的數據結構,返回True/False
cleaned_data    屬性中找到全部合法的表單數據  轉換好爲Python 的字典類型。

 

 

 

使用表單模板

 

例如:

1新建一個表單的py文件 例如:myForms.py  在app下面新建表單內容,

內容以下

#!/usr/bin/env python
#-*- coding:utf-8 -*-
from django import forms
from django.forms import  fields

class UserInfo(forms.Form):
    user = fields.CharField()
    age = fields.IntegerField()

  

2.視圖views.py

from django.shortcuts import render
from app01 import  myForms
# Create your views here.
def index(request):
    form = myForms.UserInfo()
    if request.method == 'GET':
        return render(request,'index.html',{'form':form})

  

3.路由urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import  views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),
]

  

4.模板html

經過視圖把fom表單渲染到模板的html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/index" method="POST">
    <table border="1">{{ form.as_table }}</table>
    {{ form.as_p }}
    <ul>
        {{ form.as_ul }}
    </ul>
</form>
</body>
</html>

  

上面用了幾個表單渲染,form.as_p  和 forms.as_ul  和 forms.as_table

表單渲染選項

表單模板的額外標籤
不要忘記,表單的輸出不 包含<form> 標籤,和表單的submit 按鈕
對於<label>/<input> 對,還有幾個輸出選項:

 

  1. {{ form.as_table }} 以表格的形式將它們渲染在<tr> 標籤中
  2. {{ form.as_p }} 將它們渲染在<p> 標籤中
  3. {{ form.as_ul }} 將它們渲染在<li> 標籤中

注意,你必須本身提供<table> 或<ul> 元素。

 表單字段詳解

在django的form表單api,每一個字段都是一個類,全部的字段都繼承Field這個類。
提示:多看源碼

Field這個類的經常使用參數

Field
    required=True,               是否容許爲空
    widget=None,                 HTML插件  注:重點
    label=None,                  用於生成Label標籤或顯示內容  相似HTML的label的標籤
    initial=None,                初始值	  (<input type="text" value="xixi"> 相似html的input框的value值)
    help_text='',                幫助信息(在標籤旁邊顯示)
    error_messages=None,         錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'}
    show_hidden_initial=False,   是否在當前插件後面再加一個隱藏的且具備默認值的插件(可用於檢驗兩次輸入是否一直)
    validators=[],               自定義驗證規則
    localize=False,              是否支持本地化
    disabled=False,              是否能夠編輯
    label_suffix=None            Label內容後綴  

  

經常使用字段

ChoiceField   選擇類型的字段(例如,下拉框,等等)
	choice[(1,'北京'),(2,'上海'),(3,'深圳')]   這個選項是提供下拉框的內容
	
	表單模板的額外標籤
	不要忘記,表單的輸出不 包含<form> 標籤,和表單的submit 按鈕
	對於<label>/<input> 對,還有幾個輸出選項:


	{{ form.as_table }} 以表格的形式將它們渲染在<tr> 標籤中
	{{ form.as_p }}  將它們渲染在<p> 標籤中
	{{ form.as_ul }} 將它們渲染在<li> 標籤中
	注意,你必須本身提供<table> 或<ul> 元素。
	
CharField(Field)
    max_length=None,             最大長度
    min_length=None,             最小長度
    strip=True                   是否移除用戶輸入空白

IntegerField(Field)
    max_value=None,              最大值
    min_value=None,              最小值
 
FloatField(IntegerField)
    ...
 
DecimalField(IntegerField)
    max_value=None,              最大值
    min_value=None,              最小值
    max_digits=None,             總長度
    decimal_places=None,         小數位長度

BaseTemporalField(Field)
    input_formats=None          時間格式化   
 
DateField(BaseTemporalField)    格式:2015-09-01
TimeField(BaseTemporalField)    格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12

RegexField(CharField)
    regex,                      自定製正則表達式
    max_length=None,            最大長度
    min_length=None,            最小長度
    error_message=None,         忽略,錯誤信息使用 error_messages={'invalid': '...'}

	
EmailField(CharField)      
    ...
FileField(Field)
    allow_empty_file=False     是否容許空文件

	
ImageField(FileField)      
    ...
    注:須要PIL模塊,pip3 install Pillow
    以上兩個字典使用時,須要注意兩點:
        - form表單中 enctype="multipart/form-data"
        - view函數中 obj = MyForm(request.POST, request.FILES)
 
URLField(Field)
    ...
 
 
BooleanField(Field)  
    ...
 
NullBooleanField(BooleanField)
    ...
 
ChoiceField(Field)
    ...
    choices=(),                選項,如:choices = ((0,'上海'),(1,'北京'),)
    required=True,             是否必填
    widget=None,               插件,默認select插件
    label=None,                Label內容
    initial=None,              初始值
    help_text='',              幫助提示
注:choices選項:由可迭代的二元組組成(好比[(A, B), (A, B) ...]),用來給這個字段提供選擇項。若是設置了 choices ,默認表格樣式就會顯示選擇框,而不是標準的文本框,並且這個選擇框的選項就是 choices 中的元組。 
每一個元組中的第一個元素,是存儲在數據庫中的值;第二個元素是該選項更易理解的描述


ModelChoiceField(ChoiceField)
    ...                        django.forms.models.ModelChoiceField
    queryset,                  # 查詢數據庫中的數據
    empty_label="---------",   # 默認空顯示內容
    to_field_name=None,        # HTML中value的值對應的字段
    limit_choices_to=None      # ModelForm中對queryset二次篩選
     
ModelMultipleChoiceField(ModelChoiceField)
    ...                        django.forms.models.ModelMultipleChoiceField
 
 
     
TypedChoiceField(ChoiceField)
    coerce = lambda val: val   對選中的值進行一次轉換
    empty_value= ''            空值的默認值
 
MultipleChoiceField(ChoiceField)  多選字段
    ...
 
TypedMultipleChoiceField(MultipleChoiceField)
    coerce = lambda val: val   對選中的每個值進行一次轉換
    empty_value= ''            空值的默認值
 
ComboField(Field)
    fields=()                  使用多個驗證,以下:即驗證最大長度20,又驗證郵箱格式
                               fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
 
MultiValueField(Field)
    PS: 抽象類,子類中能夠實現聚合多個字典去匹配一個值,要配合MultiWidget使用
 
SplitDateTimeField(MultiValueField)
    input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
    input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
 
FilePathField(ChoiceField)     文件選項,目錄下文件顯示在頁面中
    path,                      文件夾路徑
    match=None,                正則匹配
    recursive=False,           遞歸下面的文件夾
    allow_files=True,          容許文件
    allow_folders=False,       容許文件夾
    required=True,
    widget=None,
    label=None,
    initial=None,
    help_text=''
 
GenericIPAddressField
    protocol='both',           both,ipv4,ipv6支持的IP格式
    unpack_ipv4=False          解析ipv4地址,若是是::ffff:192.0.2.1時候,可解析爲192.0.2.1, PS:protocol必須爲both才能啓用
 
SlugField(CharField)           數字,字母,下劃線,減號(連字符)
    ...
 
UUIDField(CharField)           uuid類型
    ...

  

重點form字段

Form重點:
    - 字段
        用於保存正則表達式
        ChoiceField *****
        MultipleChoiceField
        CharField
        IntegerField
        DecimalField
        DateField
        DateTimeField
        EmailField
        GenericIPAddressField
        FileField
        
        RegexField

  

表單字段的HTML插件

全部Field字段本質上封裝了兩個東西,一個是正則表達式,一個是HTML插件

每一個表單字段都有一個對應的Widget 類,它對應一個HTML 表單Widget,例如<input type="text">。

在大部分狀況下,字段都具備一個合理的默認Widget。例如,默認狀況下,CharField 具備一個TextInput Widget,它在HTML 中生成一個<input type="text">。

 

Django內置插件

TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget

  

經常使用widget的選擇HTML插件

 不要將Widget 與表單字段搞混淆。表單字段負責驗證輸入並直接在模板中使用。Widget 負責渲染網頁上HTML 表單的輸入元素和提取提交的原始數據。可是,Widget 須要賦值給表單字段。

 

# 單radio,值爲字符串  widgets方式
# user = fields.CharField(
#     initial=2,
#     widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
# )
 
# 單radio,值爲字符串    ChoiceField選擇字段方式
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.RadioSelect
# )
 
# 單select,值爲字符串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
# )
 
# 單select,值爲字符串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.Select
# )
 
# 多選select,值爲列表
# user = fields.MultipleChoiceField(
#     choices=((1,'上海'),(2,'北京'),),
#     initial=[1,],
#     widget=widgets.SelectMultiple
# )
 
 
# 單checkbox
# user = fields.CharField(
#     widget=widgets.CheckboxInput()
# )
 
 
# 多選checkbox,值爲列表
# user = fields.MultipleChoiceField(
#     initial=[2, ],
#     choices=((1, '上海'), (2, '北京'),),
#     widget=widgets.CheckboxSelectMultiple
# )

  

提示:根據自已喜愛,選擇用widget插件,仍是ChoiceField方式

 widget只能生成form相關的html標籤,不能生成div,span標籤等等。。。。

數據實時更新

方式一:(推薦)

在使用選擇標籤時,須要注意choices的選項能夠從數據庫中獲取,可是因爲是類屬性字段 ***獲取的值沒法實時更新***,

那麼須要自定義構造方法(__init__)從而達到此目的。

 

from django.forms import Form
from django.forms import widgets
from django.forms import fields
class MyForm(Form):
 
    user = fields.ChoiceField(
        # choices=((1, '上海'), (2, '北京'),),
        initial=2,
        widget=widgets.Select
    )
 
    def __init__(self, *args, **kwargs):
        super(MyForm,self).__init__(*args, **kwargs)
        # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)
        # 或
        self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')

  

 

方式二:

依賴數據庫的model的__str__方法 

from django import forms
from django.forms import fields
from django.forms import widgets
from django.forms.models import ModelChoiceField
 
class FInfo(forms.Form):
    authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
    # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())
    to_field_name='id'  #使用id的那列字段做爲input框的value值

  

 FORM自定製匹配正則表達式的擴展

方式一

  

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
                 
class MyForm(Form):
       user = fields.CharField(
       error_messages={'invalid': '...'},
       validators=[RegexValidator(r'^[0-9]+$', '請輸入數字'), RegexValidator(r'^159[0-9]+$', '數字必須以159開頭')],
                    )

  

字段下的validator

validators=[RegexValidator(r'^[0-9]+$', '請輸入數字')]
validators 自定義匹配正則表達式,能夠有多個匹配的正則表達式,匹配順序是從前到後
RegexValidator這個類有兩個參數,第一個是正則表達式,第二個錯誤提示

 

方式二

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
                 
class MyForm(Form):
      user = fields.RegexField(r'^[0-9]+$',error_messages={'invalid': '...'})
                    

  

正則字段

 

基於源碼流程的擴展

若是某一個字段不只只是自定義正則表達式匹配,例如:還有一些用戶註冊的惟一性等等要求,這時候就要基於form源碼來擴展

單子段驗證

重寫:clean_字段名方法

from django import forms
from django.forms import fields
from django.forms import widgets
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
class AForm(forms.Form):
       username = fields.CharField()
       user_id = fields.IntegerField(
                    widget=widgets.Select(choices=[(0,'張三'),(1,'李四'),(2,'老王'),])
                )
            # 自定義方法 clean_字段名
            # 必須返回值self.cleaned_data['username']
            # 若是出錯:raise ValidationError('用戶名已存在')
       def clean_username(self):
                v = self.cleaned_data['username']
                if models.UserInfo.objects.filter(username=v).count():
                    # 總體錯了
                    # 本身詳細錯誤信息
                    raise ValidationError('用戶名已存在')
                return v
       def clean_user_id(self):
               return self.cleaned_data['user_id']

  

總體錯誤驗證

自定義clean方法

            class AForm(forms.Form):
                username = fields.CharField()
                user_id = fields.IntegerField(
                    widget=widgets.Select(choices=[(0,'張三'),(1,'李四'),(2,'老王'),])
                )
                # 自定義方法 clean_字段名
                # 必須返回值self.cleaned_data['username']
                # 若是出錯:raise ValidationError('用戶名已存在')
                def clean_username(self):
                    v = self.cleaned_data['username']
                    if models.UserInfo.objects.filter(username=v).count():
                        # 總體錯了
                        # 本身詳細錯誤信息
                        raise ValidationError('用戶名已存在')
                    return v
                def clean_user_id(self):
                    return self.cleaned_data['user_id']

                def clean(self):
                    value_dict = self.cleaned_data
                    v1 = value_dict.get('username')
                    v2 = value_dict.get('user_id')
                    if v1 == 'root' and v2==1:
                        raise ValidationError('總體錯誤信息')
                    return self.cleaned_data
相關文章
相關標籤/搜索