Django---Form表單
form組件的特點
- 數據的重置
- 校驗規則
程序執行文件, sys.path ,加載當前文件的路徑,到內存中,會執行當前文件。
在當前的sys.path 環境中查找該文件,找不到就會報錯
form表單字段
Charfiled:渲染出的text 字段, 字段名渲染出前端的"name"名稱
Required 等於 required= “required” 表示必填:瀏覽器根據標簽中,含有required ,就會自動校驗
Novalidate,告訴瀏覽器不需要驗證
Form渲染三種方式
方式一
{{ form.as_p }}
將它們渲染在<p>
標簽中
組件渲染出P、labe標簽
方式二
僅渲染出input標簽 .通過字段渲染,
註意:後端生成的Form對象,傳到前端,該變量,必須寫在form表單架構中
方式三
表單渲染的選項
對於<label>/<input>
對,還有幾個輸出選項:
{{ form.as_table }}
以表格的形式將它們渲染在<tr>
標簽中{{ form.as_p }}
將它們渲染在<p>
標簽中{{ form.as_ul }}
將它們渲染在<li>
標簽中
註意,你必須自己提供<table>
或<ul>
元素。
{{ form.as_table }}
{{ form.as_ul }}
會渲染如下:
在Django 中構建一個表單
Form 類
我們已經計劃好了我們的 HTML 表單應該呈現的樣子。在Django 中,我們的起始點是這裏:
from django.forms import Form from django.forms import widgets from django.forms import fields class MyForm(Form): user = fields.CharField( widget=widgets.TextInput(attrs={‘id‘: ‘i1‘, ‘class‘: ‘c1‘}) ) gender = fields.ChoiceField( choices=((1, ‘男‘), (2, ‘女‘),), initial=2, widget=widgets.RadioSelect ) city = fields.CharField( initial=2, widget=widgets.Select(choices=((1,‘上海‘),(2,‘北京‘),)) ) pwd = fields.CharField( widget=widgets.PasswordInput(attrs={‘class‘: ‘c1‘}, render_value=True) )
它定義一個Form
類,只帶有一個字段(your_name
)。
字段允許的最大長度通過max_length
定義。它完成兩件事情。首先,它在HTML 的<input>
上放置一個maxlength="100"
(這樣瀏覽器將在第一時間阻止用戶輸入多於這個數目的字符)。它還意味著當Django 收到瀏覽器發送過來的表單時,它將驗證數據的長度。
Form
的實例具有一個is_valid()
方法,它為所有的字段運行驗證的程序。當調用這個方法時,如果所有的字段都包含合法的數據,它將:
- 返回
True
- 將表單的數據放到
cleaned_data
屬性中。
完整的表單,第一次渲染時,看上去將像:
label for="your_name">Your name: </label> <input id="your_name" type="text" name="your_name" maxlength="100">
註意它不包含 <form>
標簽和提交按鈕。我們必須自己在模板中提供它們。
視圖
發送給Django 網站的表單數據通過一個視圖處理,一般和發布這個表單的是同一個視圖。這允許我們重用一些相同的邏輯。
當處理表單時,我們需要在視圖中實例化它:
#views.py from django.shortcuts import render from django.http import HttpResponseRedirect from .forms import NameForm def get_name(request): # if this is a POST request we need to process the form data if request.method == ‘POST‘: # create a form instance and populate it with data from the request: form = NameForm(request.POST) # check whether it‘s valid: if form.is_valid(): # process the data in form.cleaned_data as required # ... # redirect to a new URL: return HttpResponseRedirect(‘/thanks/‘) # if a GET (or any other method) we‘ll create a blank form else: form = NameForm() return render(request, ‘name.html‘, {‘form‘: form})
如果訪問視圖的是一個GET
請求,它將創建一個空的表單實例並將它放置到要渲染的模板的上下文中。這是我們在第一個訪問該URL 時預期發生的情況。
如果表單的提交使用POST
請求,那麽視圖將再次創建一個表單實例並使用請求中的數據填充form表單:form = NameForm(request.POST)
。這叫做”綁定數據至表單“(它現在是一個綁定的表單)。
我們調用表單的is_valid()
方法;如果它不為True
,我們將帶著這個表單返回到模板。這時表單不再為空(未綁定),所以HTML 表單將用之前提交的數據填充,然後可以根據要求編輯並改正它。
如果is_valid()
為True
,我們將能夠在cleaned_data
屬性中找到所有合法的表單數據。在發送HTTP 重定向給瀏覽器告訴它下一步的去向之前,我們可以用這個數據來更新數據庫或者做其它處理。
模板
我們不需要在name.html 模板中做很多工作。最簡單的例子是:
<form action="/your-name/" method="post"> {% csrf_token %} {{ form }} <input type="submit" value="Submit" /> </form>
根據{{ form }},所有的表單字段和它們的屬性將通過Django 的模板語言拆分成HTML 標記 。
註:Django 原生支持一個簡單易用的跨站請求偽造的防護。當提交一個啟用CSRF 防護的POST 表單時,你必須使用上面例子中的csrf_token 模板標簽。
現在我們有了一個可以工作的網頁表單,它通過Django Form 描述、通過視圖處理並渲染成一個HTML <form>。
Django Form 類詳解
綁定的和未綁定的表單實例
綁定的和未綁定的表單 之間的區別非常重要:
- 未綁定的表單沒有關聯的數據。當渲染給用戶時,它將為空或包含默認的值。
- 綁定的表單具有提交的數據,因此可以用來檢驗數據是否合法。如果渲染一個不合法的綁定的表單,它將包含內聯的錯誤信息,告訴用戶如何糾正數據。
字段詳解
考慮一個比上面的迷你示例更有用的一個表單,我們完成一個更加有用的註冊表單:
#forms.py from django import forms class RegisterForm(forms.Form): username = forms.CharField(max_length=100, error_messages={"min_length":"最短為5個字符","required":"該字段不能為空"}, ) password = forms.CharField(max_length=100, widget=widgets.PasswordInput(attrs={"placeholder":"password"}) ) telephone=forms.IntegerField( error_messages={ "invalid":"格式錯誤" } ) gender=forms.CharField( initial=2, widget=widgets.Select(choices=((1,‘上海‘),(2,‘北京‘),)) ) email = forms.EmailField() is_married = forms.BooleanField(required=False)
Widgets
每個表單字段都有一個對應的Widget
類,它對應一個HTML 表單Widget
,例如<input type="text">
。
在大部分情況下,字段都具有一個合理的默認Widget。例如,默認情況下,CharField
具有一個TextInput Widget
,它在HTML 中生成一個<input type="text">
。
不管表單提交的是什麽數據,一旦通過調用is_valid()
成功驗證(is_valid()
返回True
),驗證後的表單數據將位於form.cleaned_data
字典中。這些數據已經為你轉換好為Python 的類型。
註:此時,你依然可以從request.POST
中直接訪問到未驗證的數據,但是訪問驗證後的數據更好一些。
在上面的聯系表單示例中,is_married將是一個布爾值。類似地,IntegerField
和FloatField
字段分別將值轉換為Python 的int
和float
。
使用表單模板
你需要做的就是將表單實例放進模板的上下文。如果你的表單在Contex
t 中叫做form
,那麽{{ form }}
將正確地渲染它的<label>
和 <input>
元素。
手工渲染字段
我們沒有必要非要讓Django 來分拆表單的字段;如果我們喜歡,我們可以手工來做(例如,這樣允許重新對字段排序)。每個字段都是表單的一個屬性,可以使用{{ form.name_of_field }}
訪問,並將在Django 模板中正確地渲染。例如:
<div class="fieldWrapper"> {{ form.Username.errors }} {{ form.Username.label_tag }} {{ form.Username }} </div>
渲染表單的錯誤信息
registerForm=RegisterForm(request.POST) print(type(registerForm.errors)) #<class ‘django.forms.utils.ErrorDict‘> print(type(registerForm.errors["username"])) #<class ‘django.forms.utils.ErrorList‘>
2、使用{{ form.name_of_field.errors }}
顯示表單錯誤的一個清單,並渲染成一個ul
。看上去可能像:
<ul class="errorlist"> <li>Sender is required.</li> </ul>
form組件的鉤子
def foo(request): if request.method=="POST": regForm=RegForm(request.POST) if regForm.is_valid(): pass # 可用數據: regForm.cleaned_data, # 將數據插入數據庫表中 else: pass # 可用數據: regForm.errors # 可以利用模板渲染講errors嵌套到頁面中返回 # 也可以打包到一個字典中,用於ajax返回 else: regForm=RegForm() return render(request,"register.html",{"regForm":regForm}) ‘‘‘ 實例化時: self.fields={ "username":"字段規則對象", "password":"字段規則對象", } is_valid時: self._errors = {} self.cleaned_data = {} #局部鉤子: for name, field in self.fields.items(): try: value = field.clean(value) self.cleaned_data[name] = value if hasattr(self, ‘clean_%s‘ % name): value = getattr(self, ‘clean_%s‘ % name)() self.cleaned_data[name] = value except ValidationError as e: self.add_error(name, e) # 全局鉤子: self.clean() # def self.clean():return self.cleaned_data return not self.errors # True或者False ‘‘‘
form組件補充
1、Django內置字段如下:
Field required=True, 是否允許為空 widget=None, HTML插件 label=None, 用於生成Label標簽或顯示內容 initial=None, 初始值 help_text=‘‘, 幫助信息(在標簽旁邊顯示) error_messages=None, 錯誤信息 {‘required‘: ‘不能為空‘, ‘invalid‘: ‘格式錯誤‘} show_hidden_initial=False, 是否在當前插件後面再加一個隱藏的且具有默認值的插件(可用於檢驗兩次輸入是否一直) validators=[], 自定義驗證規則 localize=False, 是否支持本地化 disabled=False, 是否可以編輯 label_suffix=None Label內容後綴 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 DurationField(Field) 時間間隔:%d %H:%M:%S.%f ... 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=‘‘, 幫助提示 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類型 ...View Code
2、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
View Code
3、常用選擇插件:
# 單radio,值為字符串 # 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 # )View Code
4、Django內置字段如下:
Field required=True, 是否允許為空 widget=None, HTML插件 label=None, 用於生成Label標簽或顯示內容 initial=None, 初始值 help_text=‘‘, 幫助信息(在標簽旁邊顯示) error_messages=None, 錯誤信息 {‘required‘: ‘不能為空‘, ‘invalid‘: ‘格式錯誤‘} show_hidden_initial=False, 是否在當前插件後面再加一個隱藏的且具有默認值的插件(可用於檢驗兩次輸入是否一直) validators=[], 自定義驗證規則 localize=False, 是否支持本地化 disabled=False, 是否可以編輯 label_suffix=None Label內容後綴 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 DurationField(Field) 時間間隔:%d %H:%M:%S.%f ... 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=‘‘, 幫助提示 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類型 ...View Code
註:UUID是根據MAC以及當前時間等創建的不重復的隨機字符串
>>> import uuid # make a UUID based on the host ID and current time >>> uuid.uuid1() # doctest: +SKIP UUID(‘a8098c1a-f86e-11da-bd1a-00112444be1e‘) # make a UUID using an MD5 hash of a namespace UUID and a name >>> uuid.uuid3(uuid.NAMESPACE_DNS, ‘python.org‘) UUID(‘6fa459ea-ee8a-3ca4-894e-db77e160355e‘) # make a random UUID >>> uuid.uuid4() # doctest: +SKIP UUID(‘16fd2706-8baf-433b-82eb-8c7fada847da‘) # make a UUID using a SHA-1 hash of a namespace UUID and a name >>> uuid.uuid5(uuid.NAMESPACE_DNS, ‘python.org‘) UUID(‘886313e1-3b8a-5372-9b90-0c9aee199e5d‘) # make a UUID from a string of hex digits (braces and hyphens ignored) >>> x = uuid.UUID(‘{00010203-0405-0607-0809-0a0b0c0d0e0f}‘) # convert a UUID to a string of hex digits in standard form >>> str(x) ‘00010203-0405-0607-0809-0a0b0c0d0e0f‘ # get the raw 16 bytes of the UUID >>> x.bytes b‘\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f‘ # make a UUID from a 16-byte string >>> uuid.UUID(bytes=x.bytes) UUID(‘00010203-0405-0607-0809-0a0b0c0d0e0f‘)View Code
創建一個form_obj的實例對象,實例對象調用is_valid()方法,進行字段調用。
根據創建Form 根
修改form字段的標簽type類型
設置form字段的標簽 class 屬性
校驗字段 自定義字段
自定義全局錯誤--前端獲取
{{ form_obj.repwd }} <span>{{ form_obj.errors.repwd.0 }}{{ form_obj.non_field_errors.0 }}</span>form表單驗證信息
form表單驗證信息,前提是以鍵值對的形式獲取後進行驗證。前端“input”標簽的 “name”值,作為鍵,input的字段屬性作為值。如果字段無問題,會保存在“clend_data”中, 有問題的字段保存在error中Django---Form表單