咱們以前在HTML頁面中利用form表單向後端提交數據時,都會寫一些獲取用戶輸入的標籤而且用form標籤把它們包起來。 與此同時咱們在好多場景下都須要對用戶的輸入作校驗,好比校驗用戶是否輸入,輸入的長度和格式等正不正確。若是用戶輸入的內容有錯誤就須要在頁面上相應的位置顯示對應的錯誤信息.。 Django form組件就實現了上面所述的功能。 總結一下,其實form組件的主要功能以下: 生成頁面可用的HTML標籤 對用戶提交的數據進行校驗 保留上次輸入內容
寫一個form組件的實例:html
# 導入相關的包forms from django import forms # 自定義一個類讓它繼承forms.Form類 class UserInfo(forms.Form): # 寫你須要的在前端顯示的form內的相關標籤,經過對象調用會自動生成 name = forms.CharField( # 在前端頁面中顯示定義的內容,這個屬性的名稱 label='姓名:' # 自定義錯誤信息,在每一個屬性中單獨定製,會針對每一個標籤提交的錯誤信息返回不一樣的報錯提示信息 error_messages={ "required":"不能爲空!" "invalid": "格式錯誤", "min_length": "用戶名最短8位" } ) password = forms.CharField( label='密碼:', widget = forms.widgets.PasswordInput() # 給這個字段設置屬性,輸入的時候一密文形式 )
視圖函數的語法操做:前端
def index(request): # 實例化這個對象,操做類中的屬性 u_obj = UserInfo() if request.method == 'GET': return render(request,'index.html',{'u_obj':u_obj}) # 將這個對象經過render在前端頁面進行渲染 u_obj = UserInfo(request.POST) # 前端頁面提交過來的數據是:{'name':'xx','password'='123'} # 校驗數據的過程,根據前端提交的數據去類中找對應的屬性,進行校驗 if u_obj.is_valid(): # 校驗用戶提交的數據,所有校驗成功返回True,任意一個失敗都返回False return HttpResponse('ok') return render(request, 'index.html', {'u_obj': u_obj})
前端文件中的操做方式:python
<form action="" novalidate> <!-- novalidate 告訴前端form表單,不要對輸入的內容作校驗--> <div> <!--經過對象直接能夠調用類中的屬性, u_obj.name.label 顯示的是當前這個標籤的名稱 --> <!-- u_obj.name 直接就會生成對應的標籤--> {{ u_obj.name.label }} {{ u_obj.name }} {{ u_obj.name.errors.0 }} <!-- u_obj.name.errors.0 打印對應的錯誤信息,因爲errors是所有的錯誤,因此須要 .0 獲取第一個--> </div> <div> {{ u_obj.password.label }} {{ u_obj.password }} </div> </form>
form經常使用字段和插件:git
initial正則表達式
初始值,input框裏面的初始值。數據庫
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用戶名", initial="張三" # 設置默認值 ) pwd = forms.CharField(min_length=6, label="密碼")
error_messagesdjango
重寫錯誤信息。後端
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用戶名", initial="張三", error_messages={ "required": "不能爲空", "invalid": "格式錯誤", "min_length": "用戶名最短8位" } ) pwd = forms.CharField(min_length=6, label="密碼")
passwordsession
class LoginForm(forms.Form): ... pwd = forms.CharField( min_length=6, label="密碼", widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True) #這個密碼字段和其餘字段不同,默認在前端輸入數據錯誤的時候,點擊提交以後,默認是不保存的原來數據的,可是能夠經過這個render_value=True讓這個字段在前端保留用戶輸入的數據 )
radioSelect函數
單radio值爲字符串
class LoginForm(forms.Form): username = forms.CharField( #其餘選擇框或者輸入框,基本都是在這個CharField的基礎上經過插件來搞的 min_length=8, label="用戶名", initial="張三", error_messages={ "required": "不能爲空", "invalid": "格式錯誤", "min_length": "用戶名最短8位" } ) pwd = forms.CharField(min_length=6, label="密碼") gender = forms.fields.ChoiceField( choices=((1, "男"), (2, "女"), (3, "保密")), label="性別", initial=3, widget=forms.widgets.RadioSelect() )
單選Select
class LoginForm(forms.Form): ... hobby = forms.fields.ChoiceField( #注意,單選框用的是ChoiceField,而且裏面的插件是Select,否則驗證的時候會報錯, Select a valid choice的錯誤。 choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ), label="愛好", initial=3, widget=forms.widgets.Select() )
多選Select
class LoginForm(forms.Form): ... hobby = forms.fields.MultipleChoiceField( #多選框的時候用MultipleChoiceField,而且裏面的插件用的是SelectMultiple,否則驗證的時候會報錯。 choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ), label="愛好", initial=[1, 3], widget=forms.widgets.SelectMultiple() )
單選checkbox
class LoginForm(forms.Form): ... keep = forms.fields.ChoiceField( label="是否記住密碼", initial="checked", widget=forms.widgets.CheckboxInput() )
單選checkbox示例:
#單選的checkbox class TestForm2(forms.Form): keep = forms.ChoiceField( choices=( ('True',1), ('False',0), ), label="是否7天內自動登陸", initial="1", widget=forms.widgets.CheckboxInput(), ) 選中:'True' #form只是幫咱們作校驗,校驗選擇內容的時候,就是看在沒在咱們的choices裏面,裏面有這個值,表示合法,沒有就不合法 沒選中:'False' ---保存到數據庫裏面 keep:'True' if keep == 'True': session 設置有效期7天 else: pass
多選checkbox
class LoginForm(forms.Form): ... hobby = forms.fields.MultipleChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),), label="愛好", initial=[1, 3], widget=forms.widgets.CheckboxSelectMultiple() )
from django import forms from django.forms import widgets class BookForm(forms.Form): date = forms.DateField(widget=widgets.TextInput(attrs={'type':'date'})) #必須指定type,否則不能渲染成選擇時間的input框
choice字段注意事項
在使用選擇標籤時,須要注意choices的選項能夠配置從數據庫中獲取,可是因爲是靜態字段 獲取的值沒法實時更新,須要重寫構造方法從而實現choice實時更新。
方式一:
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) #注意重寫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 = forms.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) # 多選 #或者下面這種方式,經過forms裏面的models中提供的方法也是同樣的。 authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) # 多選 #authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all()) # 單選 #或者,forms.ModelChoiceField(queryset=models.Publisth.objects.all(),widget=forms.widgets.Select()) 單選 # authors = forms.ModelMultipleChoiceField( queryset=models.Author.objects.all(), widget = forms.widgets.Select(attrs={'class': 'form-control'} )) #若是用這種方式,別忘了model表中,NNEWType的__str__方法要寫上,否則選擇框裏面是一個個的object對象
Field required=True, 是否容許爲空 widget=None, HTML插件 label=None, 用於生成Label標籤或顯示內容 initial=None, 初始值 help_text='', 幫助信息(在標籤旁邊顯示) error_messages=None, 錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'} 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類型 複製代碼 內置字段
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.CharField( validators=[RegexValidator(r'^[0-9]+$', '請輸入數字'), RegexValidator(r'^159[0-9]+$', '數字必須以159開頭')], )
自定義驗證函數
import re from django.forms import Form from django.forms import widgets from django.forms import fields from django.core.exceptions import ValidationError # 自定義驗證規則 def mobile_validate(value): mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') if not mobile_re.match(value): # value是將提交的數據進行傳值 raise ValidationError('手機號碼格式錯誤') #自定義驗證規則的時候,若是不符合你的規則,須要本身發起錯誤 class PublishForm(Form): title = fields.CharField(max_length=20, min_length=5, error_messages={'required': '標題不能爲空', 'min_length': '標題最少爲5個字符', 'max_length': '標題最多爲20個字符'}, widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': '標題5-20個字符'})) # 使用自定義驗證規則,學須要調用的函數名 phone = fields.CharField(validators=[mobile_validate, ], error_messages={'required': '手機不能爲空'}, widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'手機號碼'})) email = fields.EmailField(required=False, error_messages={'required': u'郵箱不能爲空','invalid': u'郵箱格式錯誤'}, widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'郵箱'}))
除了上面兩種方式,咱們還能夠在Form類中定義鉤子函數,來實現自定義的驗證功能。
局部鉤子
咱們在Fom類中定義 clean_字段名() 方法,就可以實現對特定字段進行校驗。
舉個例子:
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用戶名", initial="張三", error_messages={ "required": "不能爲空", "invalid": "格式錯誤", "min_length": "用戶名最短8位" }, widget=forms.widgets.TextInput(attrs={"class": "form-control"}) ) ... # 定義局部鉤子,用來校驗username字段,以前的校驗股則還在,給你提供了一個添加一些校驗功能的鉤子 def clean_username(self): value = self.cleaned_data.get("username") if "666" in value: raise ValidationError("光喊666是不行的") else: return value
全局鉤子
咱們在Fom類中定義 clean() 方法,就可以實現對字段進行全局校驗,字段所有驗證完,局部鉤子也所有執行完以後,執行這個全局鉤子校驗。
class LoginForm(forms.Form): ... password = forms.CharField( min_length=6, label="密碼", widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}, render_value=True) ) re_password = forms.CharField( min_length=6, label="確認密碼", widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}, render_value=True) ) ... # 定義全局的鉤子,用來校驗密碼和確認密碼字段是否相同,執行全局鉤子的時候,cleaned_data裏面確定是有了經過前面驗證的全部數據 def clean(self): password_value = self.cleaned_data.get('password') re_password_value = self.cleaned_data.get('re_password') if password_value == re_password_value: return self.cleaned_data #全局鉤子要返回全部的數據 else: self.add_error('re_password', '兩次密碼不一致') #在re_password這個字段的錯誤列表中加上一個錯誤,而且clean_data裏面會自動清除這個re_password的值,因此打印clean_data的時候會看不到它 raise ValidationError('兩次密碼不一致')