<1>生成HTML標籤html
<2>驗證用戶數據(顯示錯誤信息)前端
<3>HTML Form提交保留上次提交數據python
<4>初始化頁面顯示內容jquery
建立Form類->views函數處理,驗證用戶輸入->生成HTML並保留提交內容git
<1>建立Form類ajax
#-*-coding=utf-8-*- from django.core.exceptions import ValidationError from django.forms import Form from django.forms import widgets from django.forms import fields class MyForm(Form): user = fields.CharField( required=True, min_length=3, max_length=12, label='用戶名', error_messages={'required':'用戶名不能爲空','min_length':'用戶名長度爲3-12之間','max_length':'用戶名長度爲3-12之間'}, #自定製HTML標籤和屬性 widget=widgets.TextInput(attrs={'id': 'user_name', 'class': 'name'}) ) age = fields.IntegerField( label='年齡', required=True, error_messages={'required':'年齡不能爲空','invalid':'非有效輸入'} ) gender = fields.ChoiceField( label='性別', choices=((1, '男'), (2, '女'),), initial=2,#默認初始值 widget=widgets.RadioSelect ) city = fields.CharField( label='城市', initial=2, widget=widgets.Select(choices=((1, '上海'), (2, '北京'),)) ) pwd = fields.CharField( required=True, min_length=6, max_length=12, label='密碼', error_messages={'required': '密碼不能爲空', 'min_length': '密碼長度爲6-12', 'max_length': '用戶名長度爲6-12'}, #widget=widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True) )
<2>views函數處理,驗證用戶輸入正則表達式
在views函數裏面,以GET方式請求時,建立Form對象,返回頁面,並將對象渲染到頁面,而後用戶提交數據,以POST方式發起請求,在POST請求時,將post方式提交的數據傳給Form對象,而後驗證數據的合法性,若是合法,頁面將保留提交的合法數據,若是數據不合法,將錯誤信息返回到當前頁面並渲染出來數據庫
#-*-coding=utf-8-*- from django.shortcuts import render from student_manage.views.form1 import * def index1(request): if request.method == 'GET': #生成空的html標籤,含有默認值 obj= MyForm() return render(request,'MyForm.html',{'obj':obj}) else: obj=MyForm(request.POST,request.FILES)#拿到瀏覽器請求,傳入form作驗證 if obj.is_valid():#判斷驗證是否經過 print('驗證成功', obj.cleaned_data)#驗證經過後的值是字典形式 else: print('驗證失敗', obj.errors)#返回的錯誤信息是個對象,'obj.errors.字典.0 ' 獲取第一個錯誤信息 return render(request,'MyForm.html',{'obj':obj})
<3>生成HTMLdjango
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/MyForm.html" method="POST" enctype="multipart/form-data"> {% csrf_token %} <p>{{obj.user.label }}{{ obj.user }} {{ obj.user.errors }}</p> <p>{{obj.age.label }}{{ obj.age }} {{ obj.age.errors}}</p> <p>{{obj.gender.label }}{{ obj.gender }} {{ obj.gender.errors }}</p> <p>{{obj.city.label }}{{ obj.city }} {{ obj.city.errors }}</p> <p>{{obj.pwd.label }}{{ obj.pwd }} {{ obj.pwd.errors }}</p> <input type="submit" value="提交"/> </form> </body> </html>
建立Form類->views函數處理,驗證用戶輸入->返回HttpResponse,與ajax交互->前端:驗證成功,跳轉到新頁面,驗證失敗,在當前頁面添加錯誤信息json
<1>建立Form類
與上面相同
<2>views函數處理,驗證用戶輸入
在views函數裏面,以GET方式請求時,建立Form對象,返回頁面,並將對象渲染到頁面,而後用戶提交數據,以POST方式發起請求,在POST請求時,將post方式提交的數據傳給Form對象,而後驗證數據的合法性,若是合法,經過HttpResponse將相應的狀態信息傳遞給ajax進行判斷,判斷成功後跳轉到新頁面,若是數據不合法,經過HttpResponse將相應的狀態和錯誤信息返回到ajax的arg中,在當前頁面本身添加錯誤信息
from django.shortcuts import render,HttpResponse from student_manage.views.form1 import * from django.forms.utils import ErrorDict import json def ajax(request): if request.method == 'GET': #生成空的html標籤,含有默認值 obj= MyForm() return render(request, 'ajax.html', {'obj': obj}) else: response={'status':'Verification failed','message':None} obj = MyForm(request.POST, request.FILES) # 拿到瀏覽器請求,傳入form作驗證 if obj.is_valid(): # 判斷驗證是否經過 print('驗證成功', obj.cleaned_data) response['status']= 'Verification pass' print('response:',response) return HttpResponse(json.dumps(response)) else: # print(obj.errors.as_ul()) #print(obj.errors.as_json()) print('驗證失敗',obj.errors.as_data()) response['message'] = obj.errors return HttpResponse(json.dumps(response))
<3>生成HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form id=fm action="/ajax.html" method="POST" enctype="multipart/form-data"> {% csrf_token %} {{ obj.as_p}} <input type="button" value="提交" id="saveBtn"/> </form> <script src="/static/jquery-3.1.1.js"></script> <script> $(function () { bind_save() }); function bind_save() { $("#saveBtn").click(function () { $.ajax({ url: '/ajax.html', type: 'POST', data: $('#fm').serialize(), dataType: 'JSON', success: function (arg) { if (arg.status == 'Verification pass') { console.log(arg); window.location.href = "http://www.baidu.com"; } else { console.log(arg.message); $.each(arg.message,function (key,value) { console.log(key,value); var tag=document.createElement("span"); tag.innerHTML=value[0]; $('#fm').find('input[name="'+key+'"]').after(tag); }); } } }) }) } </script> </body> </html>
注意:在生成HTML中的錯誤信息時,用到了jquery中$each()方法處理json數據
Form字段用於對用戶請求數據的驗證,本質就是封裝的正則表達式,含有默認HTML插件
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類型
插件用於自動生成HTML ,本質是調用__str__方法
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
# 單radio,值爲字符串 # user = fields.CharField( # initial=2, # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) # ) # 單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 # )
在使用選擇標籤時,須要注意choices的選項能夠從數據庫中獲取,可是因爲是靜態字段 ,獲取的值沒法實時更新,故須要自定義構造方法,當數據庫數據改變時,能隨之實時更新
實質是form組件中每一個字段都是類的數據屬性(全局變量),在類每次實例化以後,數據屬性不會發生改變,會保留上次的更新結果致使沒法動態顯示數據庫的內容
<動態綁定數據庫 法1>
每次實例化以前,更新字段的值
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.ChoiceField( initial=2, widget=widgets.Select ) def __init__(self, *args, **kwargs): super(MyForm,self).__init__(*args, **kwargs) self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')
<動態綁定數據庫 法2>
使用django提供的ModelChoiceField和ModelMultipleChoiceField字段來實現,不推薦使用此法,由於其依賴於models中的__str__方法
from django.forms import models as form_model student_classes=form_model.ModelMultipleChoiceField(queryset=models.Classes.objects.all()) # models中: # def __str__(self): # return self.title
<1>法1
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開頭')], )
<2>法2
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): 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'郵箱'}))
基於源碼流程擴展驗證方法
<1>設計數據庫
from django.db import models class UserInfo(models.Model): user=models.CharField(max_length=12) age=models.IntegerField() gender=models.IntegerField() city=models.CharField(max_length=32) pwd=models.CharField(max_length=12) email=models.CharField(max_length=32) def __str__(self): return self.user
<2>設計相關form字段和自定義驗證方法
#-*-coding=utf-8-*- from django.core.exceptions import ValidationError from django.forms import Form from django.forms import widgets from django.forms import fields from student_manage.models import * from django.core.exceptions import NON_FIELD_ERRORS, ValidationError class MyForm(Form): user = fields.CharField( required=True, min_length=3, max_length=12, label='用戶名', error_messages={'required':'用戶名不能爲空','min_length':'用戶名長度爲3-12之間','max_length':'用戶名長度爲3-12之間'}, #自定製HTML標籤和屬性 widget=widgets.TextInput(attrs={'id': 'user_name', 'placeholder': '用戶名'}) ) age = fields.IntegerField( label='年齡', required=True, widget=widgets.TextInput(attrs={'placeholder': '年齡'}), error_messages={'required':'年齡不能爲空','invalid':'非有效輸入'} ) gender = fields.IntegerField( label='性別', initial=2,#默認初始值 widget=widgets.RadioSelect(choices=((1, '男'), (2, '女'),)) ) city = fields.CharField( label='城市', initial=2, widget=widgets.Select(choices=((1, '上海'), (2, '北京'),)) ) pwd = fields.CharField( required=True, min_length=6, max_length=12, label='密碼', widget=widgets.PasswordInput( attrs={"class": "form-control", "placeholder": "密碼,必須包含數字,字母!", }), error_messages={'required': '密碼不能爲空', 'min_length': '密碼長度爲6-12', 'max_length': '用戶名長度爲6-12'}, #widget=widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True) ) email=fields.EmailField( required=True, max_length=32, widget=widgets.TextInput( attrs={ "class": "form-control", "placeholder": "請輸入您經常使用郵箱", }), error_messages={'required':'郵箱不能爲空','invalid':'郵箱格式錯誤'} ) #自定義方法:clean_字段名 #必須返回值self.cleaned_data['字段名'] #若是出錯,raise ValidationError('用戶名以存在') def clean_user(self): usernameValue=self.cleaned_data['user'] if UserInfo.objects.filter(user=usernameValue).count(): raise ValidationError('用戶名已存在') return usernameValue def clean(self): print(self.cleaned_data) value_dict=self.cleaned_data username=value_dict.get('user') email=value_dict.get('email') if UserInfo.objects.filter(user=username,email=email).count(): raise ValidationError('用戶名和郵箱聯合已存在') #驗證失敗 {'__all__': [ValidationError(['用戶名和郵箱聯合已存在'])]} #總體的錯誤信息,在前段取值時用鍵__all__取 return self.cleaned_data
<3>在views視圖中進行相關處理
from django.shortcuts import render,HttpResponse from student_manage.views.form1 import * from django.forms.utils import ErrorDict from student_manage.models import * import json def ajax(request): if request.method == 'GET': #生成空的html標籤,含有默認值 obj= MyForm() return render(request, 'ajax.html', {'obj': obj}) else: response={'status':'Verification failed','message':None} obj = MyForm(request.POST, request.FILES) # 拿到瀏覽器請求,傳入form作驗證 if obj.is_valid(): # 判斷驗證是否經過 print('驗證成功', obj.cleaned_data) response['status']= 'Verification pass' print('response:',response) UserInfo.objects.create(**obj.cleaned_data) return HttpResponse(json.dumps(response)) else: # print(obj.errors.as_ul()) #print(obj.errors.as_json()) print('驗證失敗',obj.errors.as_data()) response['message'] = obj.errors return HttpResponse(json.dumps(response))
<4>HTML設計
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form id=fm action="/ajax.html" method="POST" enctype="multipart/form-data"> {% csrf_token %} {{ obj.as_p}} <input type="button" value="提交" id="saveBtn"/> </form> <script src="/static/jquery-3.1.1.js"></script> <script> $(function () { bind_save() }); function bind_save() { $("#saveBtn").click(function () { $.ajax({ url: '/ajax.html', type: 'POST', data: $('#fm').serialize(), dataType: 'JSON', success: function (arg) { if (arg.status == 'Verification pass') { console.log(arg); window.location.href = "http://www.baidu.com"; } else { console.log(arg.message); $.each(arg.message,function (key,value) { console.log(key,value); var tag=document.createElement("span"); tag.innerHTML=value[0]; $('#fm').find('input[name="'+key+'"]').after(tag); }); } } }) }) } </script> </body> </html>
對於Form組件的錯誤信息: 注意再注意: 默認錯誤信息方式: raise ValidationError("輸入的密碼不一致!") 自定義對已拿到全部字段數據進行驗證的時候,這種方式在獲取錯誤信息時就發生改變,查看源碼發現若是有錯誤的話,他會執行self.add_error(None, e) 經過方法給字段None添加錯誤信息,查看add_error的源碼以及執行過程,發現None = NON_FIELD_ERRORS。也就是說會默認給__all__字段或 NON_FIELD_ERRORS寫上錯誤信息。緣由:內部定義的NON_FIELD_ERRORS="__all__", 獲取方式: 前端獲取 是經過obj.non_field_errors 後臺獲取是經過 obj.errors["__all__"] or obj.errors[NON_FIELD_ERRORS] 咱們知道,當報錯的時候,內部會自動去添加錯誤信息,那咱們可否手動指定某個字段的錯誤信息呢?答案是確定的。 這樣咱們本身添加異常的錯誤信息,就能直接經過{{obj.errors.passwords.0}}獲取到與其餘的無疑。 語法: self.add_error('字段名稱', 錯誤異常對象)
<1>models.py和form1.py
數據庫設計和字段驗證規則設計與上同
<2>在views視圖中進行序列化
from django.shortcuts import render,HttpResponse from student_manage.views.form1 import * from django.forms.utils import ErrorDict from student_manage.models import * from django.core import serializers import json def serialize(request): return render(request, 'serialize.html') def get_data(request): ret={'status':True,'data':None} try: #user_list=UserInfo.objects.all() #user_list結構:QuerySet【obj,obj,obj】 #serializers只能序列化QuerySet對象,而且只有QuerySet裏面爲一個個對象時,才須要用serializers序列化, #QuerySet裏面若是是字典或列表,則直接轉化爲python基本數據,而後直接用json序列化 #ret['data']=serializers.serialize('json',user_list) #user_list = UserInfo.objects.all().values('id', 'user','age','gender','city','email') #ret['data'] = list(user_list) # 前端直接打印console.log(arg.data); #[{'id': 1, 'user': 'candly', 'age': 12, 'gender': True, 'city': '成都', 'email': 'love@163.com'}, # {'id': 2, 'user': 'lucyck', 'age': 29, 'gender': 2, 'city': '北京', 'email': 'like@163.com'}] user_list = UserInfo.objects.all().values('id', 'user', 'age', 'gender', 'city', 'email') print('user_list:',user_list) ret['data'] = list(user_list) #console.log(arg.data); except Exception as e: ret['status'] = False result = json.dumps(ret) print('ret:',ret) return HttpResponse(result)
<3>前端接受數據進行相應處理
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>用戶列表</h1> <table id="tb"> <thead > <tr id="th"> </tr> </thead> <tbody > <tr id="tb"> </tr> </tbody> </table> <script src="/static/jquery-3.1.1.js"></script> <script> $(function () { initData(); }); function initData() { $.ajax({ url :'/get_data', type:'GET', dataType:'JSON', success:function (arg) { console.log(arg); if(arg.status) { //$('#tb').append(arg); // var data = JSON.parse(arg.data); console.log(arg.data); $.each(arg.data,function (i,item) { $.each(item,function (key,value) { console.log(key,value); }) }) } } }) } </script> </body> </html>
相關代碼以下
from django.forms import Form from django.forms import widgets from django.forms import fields from django.shortcuts import render,HttpResponse class UploadForm(Form): user = fields.CharField() img = fields.FileField() def upload_file(request): if request.method == 'GET': return render(request, 'upload.html') if request.method=='POST': #不經過form,直接上傳 #user = request.POST.get('user') #img = request.FILES.get('img') # img是對象(文件大小,文件名稱,文件內容。。。) #print(img.name) #print(img.size) #f = open(img.name, 'wb') #for line in img.chunks(): #f.write(line) #f.close() #return HttpResponse('...') #經過form上傳 obj = UploadForm(request.POST, request.FILES) if obj.is_valid(): user = obj.cleaned_data['user'] img = obj.cleaned_data['img'] print(img.name,img.size) f=open(img.name,'wb') for line in img.chunks(): f.write(line) f.close() return HttpResponse('...')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/upload" method="POST" enctype="multipart/form-data"> {% csrf_token %} <input type="text" name="user" /> <div style="position: relative"> <a>文件上傳</a> <input type="file" name="img" style="opacity: 0;position:absolute;top:0;left: 0;" /> </div> <input type="submit" value="提交" /> </form> </body> </html>
>>>>>待續