django Form高级(二)
一、Choice字段需要重启启动服务才能更新的原因:
1.index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action='/index/' method="post"> {% csrf_token %} <p>{{ obj.user }}</p> <p>{{ obj.pwd }}</p> <p>{{ obj.user_type }}</p> <input type="submit" value="提交"> </form> </body> </html> 2.forms.py from django import forms from django.forms import fields,widgets from app01 import models class UserInfoForm(forms.Form): #Form有两个功能: #1.验证 #2.生成Html #在新URL方式操作的时候,生成Html,在Ajax提交请求的时候,不需要生成Html user = fields.CharField( required=False, widget = widgets.Textarea(attrs={'class':'c1'}) )
#字段不能同步更新的原因: #user为类变量(静态字段),静态字段是属于类的,程序加载的时候,类中的静态字段一次性加载到内 # 在
# def __init__(self,age):
# self.age = age
# self.age为字段,为实例变量,程序加载的时候并不执行,只有在实例化的时候才执行。
pwd = fields.CharField(
max_length=12,
widget=widgets.PasswordInput(attrs={'class':'c1'})
)
user_type = fields.ChoiceField(
#choices=[(1,'普通用户'),(2,'超级用户'),]
choices=models.UserType.objects.values_list('id','name')
)
3.views.py
from django.shortcuts import render,redirect,HttpResponse
from app01.forms import UserInfoForm
def index(request):
obj = UserInfoForm()
return render(request,'index.html',{'obj':obj})
4.models.py
from django.db import models
class UserInfo(models.Model):
name=models.CharField(max_length=32)
email=models.EmailField()
def clean(self):
from django.core.exceptions import ValidationError
c=UserInfo.objects.filter(name=self.name).count()
if c:
raise ValidationError(message='用户名已经存在',code='i1')
class UserType(models.Model):
name=models.CharField(max_length=32)
def __str__(self):
return self.name
#以上实例中用户类型字段中现有(“普通用户”,“超级用户”),如果在此字段添加"游客"字段后,前台并不能马上进行更新,需要重新启动服务才能更新
实现同步更新前台数据方法:
方法一:
user_type = fields.ChoiceField(
#choices=[(1,'普通用户'),(2,'超级用户'),]
#choices=models.UserType.objects.values_list('id','name')
choices=[],
widget=widgets.Select
)
#对应的forms.py中的初始化方法,对models.py没有要求:
def __init__(self,*args,**kwargs):
super(UserInfoForm,self).__init__(*args,**kwargs)
self.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
方法二:
user_type2= fields.CharField(widget=widgets.Select(choices=[]))
#对应的forms.py中的初始化方法,对models.py没有要求:
def __init__(self,*args,**kwargs):
super(UserInfoForm,self).__init__(*args,**kwargs)
self.fields['user_type2'].widget.choices=models.UserType.objects.values_list('id','name')
方法三:
from django.forms.models import ModelChoicefield
user_type3 = ModelChoiceField(
empty_label = "请选择用户类型"
queryset = models.UserType.objects.all()
#其它参数
#queryset 查询数据库中的数据
#empty_label="--------" 默认空显示内容
#to_field_name = Noe #HTML中value的值对应的字段 option字段中的value值
#limit_choices_to = NOne #ModelForm中对queryset二次筛选
)
#无需在forms.py中进行初始化,但models.py中需要以字符串返回:
class UserType(models.Model):
name=models.CharField(max_length=32)
def __str__(self):
return self.na
事例如下:
1.views.py
from django.shortcuts import render,redirect,HttpResponse from app01.forms import UserInfoForm from app01 import models def index(request): #方法一 每次刷新页面都进行实例化: obj = UserInfoForm() #如果加上,则显示值,如 obj = UserInfoForm('user':"zhangsan") obj.fields['user_type'].choices = models.UserType.objects.values_list('id','name') #'id在前',option选项中的value值为id,如果name在前,option选项中的value值则为name
print(obj.fields)
#以上操作是在实例化后进行的操作,也就是每次刷新页面后对重新进行实例化 #OrderedDict([('user', <django.forms.fields.CharField object at 0x110f1b7b8>), ('pwd', <django.forms.fields.CharField object at 0x110f862e8>), ('user_type', <django.forms.fields.ChoiceField object at 0x110f863c8>)])
#fields字段中包含三个字段('user','pwd','user_type'),当每次程序加载的时候 #程序都会对类进行一次深拷贝,因此如果要对字段进行同步更新修改修改 def __init__(self)初始化函数, # #方法二 重写构造方法: #修改forms.py文件,添加如下内容: #def __init__(self, *args, **kwargs): # super(UserInfoForm, self).__init__(*args, **kwargs) # self.fields['user_type'].choices = models.UserType.objects.values_list('id', 'name') #'id在前',option选项中的value值为id,如果name在前,option选项中的value值则为name obj = UserInfoForm() return render(request,'index.html',{'obj':obj}) #方法三,因为choice在forms中的声明方法不同 2.index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action='/index/' method="post"> {% csrf_token %} <p>{{ obj.user }}</p> <p>{{ obj.pwd }}</p> <p>{{ obj.user_type }}</p> #方法一 <p>{{ obj.user_type2 }}</p> #方法二
<p>{{ obj.user_type2 }}</p> #方法三
<input type="submit" value="提交"> </form> </body> </html>
3.forms.py
from django import forms
from django.forms import fields,widgets
from app01 import models
class UserInfoForm(forms.Form):
#Form有两个功能:
#1.验证
#2.生成Html
#在新URL方式操作的时候,生成Html,在Ajax提交请求的时候,不需要生成Html
user = fields.CharField(
required=False,
widget = widgets.Textarea(attrs={'class':'c1'}) )
#user为类变量(静态字段),静态字段是属于类的
# def __init__(self,age):
# self.age = age
# self.age为字段,为实例变量,只有在实例化的时候才执行。
#程序加载的时候,类中的静态字段一次性加载到内存
pwd = fields.CharField(
max_length=32,
widget=widgets.PasswordInput(attrs={'class':'c1'}) )
user_type = fields.ChoiceField(
#choices=[(1,'普通用户'),(2,'超级用户'),]
#choices=models.UserType.objects.values_list('id','name') #普通方法
choices=[], widget=widgets.Select ) #方法二
user_type2= fields.CharField(widget=widgets.Select(choices=[])) #方法二
def __init__(self,*args,**kwargs):
super(UserInfoForm,self).__init__(*args,**kwargs)
self.fields['user_type'].choices = models.UserType.objects.values_list('id','name') #方法一
self.fields['user_type2'].widget.choices=models.UserType.objects.values_list('id','name') #方法二
4.models.py
from django.db import models
class UserInfo(models.Model):
name=models.CharField(max_length=32)
email=models.EmailField()
def clean(self):
from django.core.exceptions import ValidationError c=UserInfo.objects.filter(name=self.name).count() if c: raise ValidationError(message='用户名已经存在',code='i1') class UserType(models.Model): name=models.CharField(max_length=32) def __str__(self): return self.name 5.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), ]
二、Form操作---钩子
1.views.py def register(request): from app01.forms import RegisterForm from django.core.exceptions import NON_FIELD_ERRORS obj = RegisterForm(request.POST) if obj.is_valid(): obj.cleaned_data else: obj.errors #错误信息存放位置 #{ # '__all__':[] #整体错误信息 clean方法的错误信息 # 'NON_FIELD_ERRORS':[] # 'NON_FIELD_ERRORS' = '__all__' # 'user':[{'code':'required','message':'xxx'}] clean_user # 'pwd':[{'code':'required','message':'xxx'}] clean_pwd 2.forms.py from django.core.exceptions import ValidationError #对单独字段的钩子 class RegisterForm(forms.Form): user=fields.CharField() email=fields.EmailField() #执行顺序,首先验证user的正则表达式,如果正则表达式通过了,执行clean_user方法 def clean_user(self): c = models.UserInfo.objects.filter(name=self.cleaned_data['user'].count()) if not c: return self.cleaned_data['user'] #必须有返回值 else: raise ValidationError('用户名已经存在',code='xxx') def clean_email(self): return self.cleaned_data['email'] #必须有返回值 #对整体的钩子 class LoginForm(forms.Form): user = fields.CharField() pwd = fields.CharField() def clean_user(self): pass def clean_pwd(self): pass def clean(self): c= models.UserInfo.objects.filter(name=self.cleaned_data['user'],pwd=self.cleaned_data['pwd']).count() if c: return self.cleaned_data else: raise ValidationError('用户名或密码错误') def _post_clean(self): pass 3.models.py from django.db import models class UserInfo(models.Model): name=models.CharField(max_length=32) email=models.EmailField() def clean(self): from django.core.exceptions import ValidationError c=UserInfo.objects.filter(name=self.name).count() if c: raise ValidationError(message='用户名已经存在',code='i1') class UserType(models.Model): name=models.CharField(max_length=32) def __str__(self): return self.name 4.index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action='/index/' method="post"> {% csrf_token %} <p>{{ obj.user }}</p> <p>{{ obj.pwd }}</p> <p>{{ obj.user_type }}</p> <p>{{ obj.user_type2 }}</p> <p>{{ obj.user_type3 }}</p> <input type="submit" value="提交"> </form> </body> </html> 5.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), ]
三、序列化
一)错误信息序列化:
1.views/account.py from django.shortcuts import render,HttpResponse from django import forms from django.forms import fields from django.forms import widgets import json class LoginForm(forms.Form): username = fields.CharField() password = fields.CharField( max_length=64, min_length=12 ) from django.core.exceptions import ValidationError class JsonCustomEncoder(json.JSONEncoder): def default(self, field): if isinstance(field,ValidationError ): return {'code':field.code,'messages':field.messages} else: return json.JSONEncoder.default(self,field) def login(request): if request.method == 'GET': return render(request,'login.html') elif request.method=='POST': ret = {'status':True,'error':None,'data':None} obj= LoginForm(request.POST) if obj.is_valid(): print("obj.cleaned_data:",obj.cleaned_data) #obj.cleaned_data: {'password': '12222222222222', 'username': 'jidi'} else: #print("obj.errors",obj.errors) #obj.errors <ul class="errorlist"><li>password<ul class="errorlist"><li>Ensure this value has at least 12 characters (it has 3).</li></ul></li></ul> #print(type(obj.errors)) for k,v in obj.errors.as_data().items(): print(k,v) #username [ValidationError(['This field is required.'])] ---->虽然as_data序列化后是字典,但字典内的值为ValidationError,json不能对其进行序列化 #password [ValidationError(['Ensure this value has at least 12 characters (it has 9).'])] from django.core.exceptions import ValidationError #<class 'django.forms.utils.ErrorDict'> #from django.forms.utils import ErrorDict #继承了字典,包括几个函数: #1.as_data ---->把字段转换成字典 #2.as_json ---->把字段转换成字符串 #3.as_ul ---->把字段转换成html #4.as_text ---->把字段转换成文本 #ret['error'] = obj.errors.as_json() #js的console中输出: # {"error": "{\"password\": [{\"message\": \"Ensure this value has at least 12 characters (it has 9).\", \"code\": \"min_length\"}]}", "data": null, "status": true} #把最终的字符串error付值给ret #a = obj.errors.as_text() #print("a:",a) #a: * password # * Ensure this value has at least 12 characters (it has 9). #b = obj.errors.as_ul() #print("b:",b) #b: <ul class="errorlist"><li>password<ul class="errorlist"><li>Ensure this value has at least 12 characters (it has 9).</li></ul></li></ul> #c = obj.errors.as_data() #print("c:",c) #c: {'password': [ValidationError(['Ensure this value has at least 12 characters (it has 9).'])]} ret['error'] = obj.errors.as_data() result = json.dumps(ret,cls=JsonCustomEncoder) print(result) #{"error": {"password": [{"messages": ["Ensure this value has at least 12 characters (it has 9)."], "code": "min_length"}], "username": [{"messages": ["This field is required."], "code": "required"}]}, "status": true, "data": null} return HttpResponse(result) #json.dupms 序列化成字符串 2.login.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form id="fm"> {% csrf_token %} <p><input type="text" name="username"></p> <p><input type="password" name="password"></p> <a id="submit">提交</a> </form> <script src="/static/jquery.min.js"></script> <script> $(function(){ $('#submit').click(function(){ $.ajax({ url:'/login.html', type:'POST', data:$('#fm').serialize(), success:function(arg){ console.log(arg); //返回字符串 //{"data": null, "status": true, "error": "{\"password\": [{\"message\": \"Ensure this value has at least 12 characters (it has 9).\", \"code\": \"min_length\"}]}"} arg = JSON.parse(arg); //把字符串转换成对像 //console.log(arg); //Object {data: null, status: true, error: "{"password": [{"message": "Ensure this value has a… characters (it has 9).", "code": "min_length"}]}"} //arg.error = JSON.parse(arg.error); //把arg对象中的error字符串转化为对象 //console.log(arg); //Object {data: null, status: true, error: Object} }, error:function(){ } }) }) }) </script> </body> </html> 3.forms.py from django import forms from django.forms import fields,widgets from app01 import models from django.forms.models import ModelChoiceField class UserInfoForm(forms.Form): #Form有两个功能: #1.验证 #2.生成Html #在新URL方式操作的时候,生成Html,在Ajax提交请求的时候,不需要生成Html user = fields.CharField( required=False, widget = widgets.Textarea(attrs={'class':'c1'}) ) #user为类变量(静态字段),静态字段是属于类的 # 在 # def __init__(self,age): # self.age = age # self.age为字段,为实例变量,只有在实例化的时候才执行。 #程序加载的时候,类中的静态字段一次性加载到内存 pwd = fields.CharField( max_length=32, widget=widgets.PasswordInput(attrs={'class':'c1'}) ) user_type = fields.ChoiceField( #choices=[(1,'普通用户'),(2,'超级用户'),] #choices=models.UserType.objects.values_list('id','name') choices=[], widget=widgets.Select ) user_type2= fields.CharField(widget=widgets.Select(choices=[])) user_type3 = ModelChoiceField( empty_label= "请选择用户类型", to_field_name= 'name', queryset = models.UserType.objects.all() ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type'].choices = models.UserType.objects.values_list('id','name') self.fields['user_type2'].widget.choices=models.UserType.objects.values_list('id','name') from django.core.exceptions import ValidationError #对单独字段的钩子 class RegisterForm(forms.Form): user=fields.CharField() email=fields.EmailField() #执行顺序,首先验证user的正则表达式,如果正则表达式通过了,执行clean_user方法 def clean_user(self): c = models.UserInfo.objects.filter(name=self.cleaned_data['user'].count()) if not c: return self.cleaned_data['user'] #必须有返回值 else: raise ValidationError('用户名已经存在',code='xxx') def clean_email(self): return self.cleaned_data['email'] #必须有返回值 #对整体的钩子 class LoginForm(forms.Form): user = fields.CharField() pwd = fields.CharField() def clean(self): c= models.UserInfo.objects.filter(
name=self.cleaned_data['user'],
pwd=self.cleaned_data['pwd']).count() if c: return self.cleaned_data else: raise ValidationError('用户名或密码错误') def _post_clean(self): pass 4.urls.py from django.conf.urls import url from django.contrib import admin from app01.views import test,account urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', test.index), url(r'^login.html$', account.login), ]
二)对Queryset序列化:
第一种: from django.core import serializers v = models.tb.objects.all() #---->返回对象,使用serizlizers进行序列化 data = serializers.serialize("json",v) 第二种: v = models.tb.objects.values('id','name') #---->返回为字典,然后转化成列表进行序列化 v = list(v) v = json.dumps(v) #如果返回对象中有datetime,则需使用JSONEncoder进行序列化 import json from datetime import date from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): def default(self,field): if isinstance(field,datetime): return field.strftime('%Y-%m-%d %H:%M:%S' elif isinstance(field,date): return field.strftime('%Y-%m-%d') else: return json.JSONEncoder.default(self.field) v = models.tb.objects.values('id','name','ctime') v = list(v) v = json.dumps(v,cls=JsonCustomEncoder) )
浙公网安备 33010602011771号