內置的Django form組件操做更加簡單html
在html文件中建立好form表單並作好排版,而後動態數據經過後臺函數提供前端
views.pygit
1 def register(request): 2 error_msg = "" 3 if request.method == "POST": 4 username = request.POST.get("name") 5 pwd = request.POST.get("pwd") 6 # 對註冊信息作校驗 7 if len(username) < 6: 8 # 用戶長度小於6位 9 error_msg = "用戶名長度不能小於6位" 10 else: 11 # 將用戶名和密碼存到數據庫 12 return HttpResponse("註冊成功") 13 return render(request, "register.html", {"error_msg": error_msg})
login.html正則表達式
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>註冊頁面</title> 6 </head> 7 <body> 8 <form action="/reg/" method="post"> 9 {% csrf_token %} 10 <p> 11 用戶名: 12 <input type="text" name="name"> 13 </p> 14 <p> 15 密碼: 16 <input type="password" name="pwd"> 17 </p> 18 <p> 19 <input type="submit" value="註冊"> 20 <p style="color: red">{{ error_msg }}</p> 21 </p> 22 </form> 23 </body> 24 </html>
在後臺函數建立好form類實例化後和動態數據一塊兒傳到前端HTML文件,再由HTML文件排版數據庫
form.py
(一般會將 form 表單的操做在 一個單獨的文件裏面寫 這樣和model.py同級便於區分)django
1 from django import forms 2 # 按照Django form組件的要求本身寫一個類 3 class RegForm(forms.Form): 4 name = forms.CharField(label="用戶名") 5 pwd = forms.CharField(label="密碼")
views.py框架
1 def register2(request): 2 form_obj = RegForm() 3 if request.method == "POST": 4 # 實例化form對象的時候,把post提交過來的數據直接傳進去 5 form_obj = RegForm(request.POST) 6 # 調用form_obj校驗數據的方法 7 if form_obj.is_valid(): 8 return HttpResponse("註冊成功") 9 return render(request, "register2.html", {"form_obj": form_obj})
login2.htmlide
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>註冊2</title> </head> <body> <form action="/reg2/" method="post" novalidate autocomplete="off"> {% csrf_token %} <div> <label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}</label> {{ form_obj.name }} {{ form_obj.name.errors.0 }} </div> <div> <label for="{{ form_obj.pwd.id_for_label }}">{{ form_obj.pwd.label }}</label> {{ form_obj.pwd }} {{ form_obj.pwd.errors.0 }} </div> <div> <input type="submit" class="btn btn-success" value="註冊"> </div> </form> </body> </html>
標籤內顯示內容函數
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用戶名", # 顯示內容 )
初始值,input框裏面的初始值。post
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用戶名", initial="張三" # 設置默認值)
重寫錯誤信息。
內置字段格式:
「錯誤類型」:「錯誤顯示信息」
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用戶名", initial="張三", error_messages={
"required": "不能爲空", "invalid": "格式錯誤", "min_length": "用戶名最短8位" } )
插件,添加 各種的HTML 的標籤,並調整屬性樣式等操做,對每一種標籤除了經常使用的屬性之外都有不一樣的屬性值能夠設置
class LoginForm(forms.Form): pwd = forms.CharField( min_length=6, label="密碼", widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True) )
密碼類型input標籤
class LoginForm(forms.Form): pwd = forms.CharField( min_length=6, label="密碼", widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True) )
class LoginForm(forms.Form): gender = forms.fields.ChoiceField( choices=((1, "男"), (2, "女"), (3, "保密")), label="性別", initial=3, widget=forms.widgets.RadioSelect() )
class LoginForm(forms.Form): hobby = forms.fields.MultipleChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ), label="愛好", initial=[1, 3], widget=forms.widgets.SelectMultiple() )
class LoginForm(forms.Form): keep = forms.fields.ChoiceField( label="是否記住密碼", initial="checked", widget=forms.widgets.CheckboxInput() )
class LoginForm(forms.Form): ... hobby = forms.fields.MultipleChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),), label="愛好", initial=[1, 3], widget=forms.widgets.CheckboxSelectMultiple() )
choices的選項能夠配置從數據庫中獲取,可是因爲是靜態字段 獲取的值沒法實時更新,須要重寫 構造方法 從而實現choice實時更新。
方式一:
重寫 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'].choices = ((1, '上海'), (2, '北京'),) # 或 self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption')
方式二:
from django import forms from django.forms import fields from django.forms import models as form_model class FInfo(forms.Form): authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) # 多選 # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all()) # 單選
1 Field 2 required=True, 是否容許爲空 3 widget=None, HTML插件 4 label=None, 用於生成Label標籤或顯示內容 5 initial=None, 初始值 6 help_text='', 幫助信息(在標籤旁邊顯示) 7 error_messages=None, 錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'} 8 validators=[], 自定義驗證規則 9 localize=False, 是否支持本地化 10 disabled=False, 是否能夠編輯 11 label_suffix=None Label內容後綴 12 13 14 CharField(Field) 15 max_length=None, 最大長度 16 min_length=None, 最小長度 17 strip=True 是否移除用戶輸入空白 18 19 IntegerField(Field) 20 max_value=None, 最大值 21 min_value=None, 最小值 22 23 FloatField(IntegerField) 24 ... 25 26 DecimalField(IntegerField) 27 max_value=None, 最大值 28 min_value=None, 最小值 29 max_digits=None, 總長度 30 decimal_places=None, 小數位長度 31 32 BaseTemporalField(Field) 33 input_formats=None 時間格式化 34 35 DateField(BaseTemporalField) 格式:2015-09-01 36 TimeField(BaseTemporalField) 格式:11:12 37 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 38 39 DurationField(Field) 時間間隔:%d %H:%M:%S.%f 40 ... 41 42 RegexField(CharField) 43 regex, 自定製正則表達式 44 max_length=None, 最大長度 45 min_length=None, 最小長度 46 error_message=None, 忽略,錯誤信息使用 error_messages={'invalid': '...'} 47 48 EmailField(CharField) 49 ... 50 51 FileField(Field) 52 allow_empty_file=False 是否容許空文件 53 54 ImageField(FileField) 55 ... 56 注:須要PIL模塊,pip3 install Pillow 57 以上兩個字典使用時,須要注意兩點: 58 - form表單中 enctype="multipart/form-data" 59 - view函數中 obj = MyForm(request.POST, request.FILES) 60 61 URLField(Field) 62 ... 63 64 65 BooleanField(Field) 66 ... 67 68 NullBooleanField(BooleanField) 69 ... 70 71 ChoiceField(Field) 72 ... 73 choices=(), 選項,如:choices = ((0,'上海'),(1,'北京'),) 74 required=True, 是否必填 75 widget=None, 插件,默認select插件 76 label=None, Label內容 77 initial=None, 初始值 78 help_text='', 幫助提示 79 80 81 ModelChoiceField(ChoiceField) 82 ... django.forms.models.ModelChoiceField 83 queryset, # 查詢數據庫中的數據 84 empty_label="---------", # 默認空顯示內容 85 to_field_name=None, # HTML中value的值對應的字段 86 limit_choices_to=None # ModelForm中對queryset二次篩選 87 88 ModelMultipleChoiceField(ModelChoiceField) 89 ... django.forms.models.ModelMultipleChoiceField 90 91 92 93 TypedChoiceField(ChoiceField) 94 coerce = lambda val: val 對選中的值進行一次轉換 95 empty_value= '' 空值的默認值 96 97 MultipleChoiceField(ChoiceField) 98 ... 99 100 TypedMultipleChoiceField(MultipleChoiceField) 101 coerce = lambda val: val 對選中的每個值進行一次轉換 102 empty_value= '' 空值的默認值 103 104 ComboField(Field) 105 fields=() 使用多個驗證,以下:即驗證最大長度20,又驗證郵箱格式 106 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) 107 108 MultiValueField(Field) 109 PS: 抽象類,子類中能夠實現聚合多個字典去匹配一個值,要配合MultiWidget使用 110 111 SplitDateTimeField(MultiValueField) 112 input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] 113 input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] 114 115 FilePathField(ChoiceField) 文件選項,目錄下文件顯示在頁面中 116 path, 文件夾路徑 117 match=None, 正則匹配 118 recursive=False, 遞歸下面的文件夾 119 allow_files=True, 容許文件 120 allow_folders=False, 容許文件夾 121 required=True, 122 widget=None, 123 label=None, 124 initial=None, 125 help_text='' 126 127 GenericIPAddressField 128 protocol='both', both,ipv4,ipv6支持的IP格式 129 unpack_ipv4=False 解析ipv4地址,若是是::ffff:192.0.2.1時候,可解析爲192.0.2.1, PS:protocol必須爲both才能啓用 130 131 SlugField(CharField) 數字,字母,下劃線,減號(連字符) 132 ... 133 134 UUIDField(CharField) uuid類型 135 136 Django Form內置字段
直接將 form 類中的全部標籤以默認的方式總體生成
操縱更加簡單,可是默認會添加不少的沒必要要的屬性
並且不方便控制form表單的總體樣式
{{ form.as_p }}
本身寫form表單框架,可是標籤內容用form 組件來填充循環一個一個生成
對於form表單的樣式能夠調節了,可是生成的標籤依舊不少沒必要要的屬性
<form action="/reg2/" method="post" novalidate autocomplete="off"> {% csrf_token %}
<div> <label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}</label> {{ form_obj.name }} {{ form_obj.name.errors.0 }} </div>
<div> <label for="{{ form_obj.pwd.id_for_label }}">{{ form_obj.pwd.label }}</label> {{ form_obj.pwd }} {{ form_obj.pwd.errors.0 }} </div>
<div> <input type="submit" class="btn btn-success" value="註冊"> </div> </form>
徹底不用form組件的標籤生成,所有手動寫
徹底控制了標籤的樣式自由
再也不須要基於form組件的內置字段來控制樣式
<form action="/addbook/" method="post"> {% csrf_token %} <p>名稱<input type="text" name="title"></p> <p>價格<input type="text" name="price"></p> <input type="submit"> </form>
ps:
可是我仍是想要用form 組件的 驗證功能則須要注意一點 : 本身寫的標籤的 「 name 」 屬性必定要和 form 組件要驗證的字段名字對的上
class BookForm(forms.Form): title = forms.CharField() price = forms.FloatField() def addbook(request): if request.method == "POST": print(request.POST) form = BookForm(request.POST) if form.is_valid(): print("cleaned_data", form.cleaned_data) else: print("errors", form.errors) form = BookForm() return render(request, "addbook.html", locals())
詳解:
面代碼中 BookForm 註冊的字段名字爲 「 title 」 以及 「 price 」
那麼本身手寫的 標籤的 「 name 」 屬性必定要和這個對上才能夠
<form action="/addbook/" method="post"> {% csrf_token %} <p>名稱<input type="text" name="title"></p> <p>價格<input type="text" name="price"></p> <input type="submit"> </form>
在校驗的時候,
若是 BookForm 中要求字段比 實際傳入的字段要少 ,會引起空數據的 error (至關於有數據沒拿到)
若是 BookForm 中要求字段比 實際傳入的字段要多 , BookForm 對要求驗證字段驗證結束無錯誤後是不會處理多餘的字段的。
最明顯的特徵爲 csrf_token 的值不會進行處理也不會報錯
1 # 重寫全局的鉤子函數,對確認密碼作校驗 2 from django.core.exceptions import ValidationError 3 4 5 def clean(self): 6 password = self.cleaned_data.get("password") 7 re_password = self.cleaned_data.get("re_password") 8 if re_password and re_password != password: 9 self.add_error("re_password", ValidationError("兩次密碼不一致")) 10 return self.cleaned_data 11 12 13 14 15 # 重寫局部鉤子函數 對名字字段的敏感字符進行判斷 16 from django.core.exceptions import ValidationError 17 18 19 def clean_name(self): 20 value = self.cleaned_data.get("name") 21 if "金瓶mei" in value: 22 raiseValidationError("不符合社會主義核心價值觀!") 23return value
0. form is_vaild()
1. 判斷是否有數據 以及 是否有錯誤 (是否有數據直接能夠判斷)
2 . 進行錯誤信息的判斷 (默認的錯誤信息爲 none 定義在 init 中)
2.1 執行 full_clean()方法
2.1.1 建立一個 保存錯誤信息的 空字典 ( self._error = ErroDict() )
2.2.2 建立一個 保存校驗經過數據的 空字典 ( self.cleaned_data = {} )
2.2 而後分別執行下面的三個方法
2.2.1 _clean_fields()
2.2.1.1 for 循環每一個字段 ( self.fields.items() ) 分別校驗 ( 利用的是內置的校驗規則 )
若是有錯誤 在 self._error[] 中 在 add_error 中能夠捕獲到 ValidationError 異常進行處理 (稍微有些廢話就隱藏把)
若是沒有報錯 在cleaned_date[] 中 加入已經經過校驗的字段
2.2.1.2 for 循環結束後 進行一次反射 查詢是否有 clean_%s %name 的方法 進行調用後執行
若是有錯誤 在 self._error[] 中 在 add_error 中能夠捕獲到 ValidationError 異常進行處理 (稍微有些廢話就隱藏把)
若是沒有報錯 在cleaned_date[] 中 加入已經經過校驗的字段
即 這個 clean_%s 的方法爲一個鉤子函數 此鉤子能夠幫咱們解決什麼問題呢?
這是個局部變量的鉤子 能夠對局部變量內部進行必定程度的操做 好比對變量的值進行操做
2.2.2 _clean_form()
調用對象的 .clean()方法,默認的繼承的 .clean() 是什麼都不作的
即 .clean() 爲一個全局的鉤子 能夠對全部的變量進行操做 好比兩個變量的對比等
所以能夠利用這個clean方法進行 重寫 自定義想要的校驗操做
2.2.3 post_clean()
經過上面的流程能夠發現.不管是使用全局鉤子仍是局部鉤子都是對已經校驗經過的數據進行操做
便是說 在調用 def clean_name(self): 或者 def clean(self): 的時候
self.cleaned_data 裏面已經裝好了校驗經過的數據對象
在調用 def clean(self): 經過get("name") 也能夠拿到全部的變量對象
在調用 def clean_name(self): 經過get("name") 也能夠拿到當前的局部變量對象
經過後面的流程也發現這兩個函數都要有返回值
def clean(self): 須要返回全局的 self.cleaned_data
ddef clean_name(self): 須要返回被處理的局部變量 value