在HTML中,表單是<form>...</form> 之間元素的集合,它們容許訪問者輸入文本、選擇選項、操做對象和控制等等,而後將信息發送回服務器。html
某些表單的元素 —— 文本輸入和複選框 —— 很是簡單並且內建於HTML 自己。其它的表單會複雜些;例如彈出一個日期選擇對話框的界面、容許你移動滾動條的界面、使用JavaScript 和CSS 以及HTML 表單<input> 元素來實現操做控制的界面。與<input> 元素同樣,一個表單必須指定兩樣東西:前端
例如,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 的Form 類。Django 的模型描述一個對象的邏輯結構、行爲以及展示給咱們的方式,與此相似,Form 類描述一個表單並決定它如何工做和展示。數據庫
就像模型類的屬性映射到數據庫的字段同樣,表單類的字段會映射到HTML 的<input>表單的元素。django
表單字段在瀏覽器中呈現給用戶的是一個HTML 的「widget」 —— 用戶界面的一個片斷。每一個字段類型都有一個合適的默認Widget 類,須要時能夠覆蓋。api
widget 部件瀏覽器
在Django 中渲染一個對象時,咱們一般:服務器
在模板中渲染表單和渲染其它類型的對象幾乎同樣,除了幾個關鍵的差異。
在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> 對,還有幾個輸出選項:
注意,你必須本身提供<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
全部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 與表單字段搞混淆。表單字段負責驗證輸入並直接在模板中使用。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值
方式一
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