Django ModelForm操作及验证方式
一、内容回顾
Model
-数据库操作
-验证
classA(MOdel):
user=
email=
pwd=
Form
-classLoginForm(Form):
email=fields.EmailField()
user=
pwd=-is_valid->每一个字段进行正则(字段内置正则)+clean_字段->clean(__all__)->_post_clean
-cleand_data
-error
-------->推荐Form<---------
二、ModelForm操作及验证
Model+Form==>ModelForm。model和form的结合体,所以有以下功能:
数据验证
数据库操作
model有操作数据库的字段,form验证也有那几个字段,虽然耦合度降低,但是代码是有重复的。如果利用model里的字段,那是不是form里的字段就不用写了。
1、Model+Form(之前的操作)
models.py
classUserType(models.Model): caption=models.CharField(max_length=32) classUserInfo(models.Model): username=models.CharField(max_length=32) email=models.EmailField() user_type=models.ForeignKey(to='UserType',to_field='id')
forms.py
fromdjangoimportforms
fromdjango.formsimportfields
classUserInfoForm(forms.Form):
#username=models.CharField(max_length=32)<--models
username=fields.CharField(max_length=32)
#email=models.EmailField()<--models
email=fields.EmailField()
#user_type=models.ForeignKey(to='UserType',to_field='id')<--models
user_type=fields.ChoiceField(
choices=models.UserType.objects.values_list('id','caption')
)
#下面的操作是让数据在网页上实时更新。
def__init__(self,*args,**kwargs):
super(UserInfoForm,self).__init__(*args,**kwargs)
self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption')
index.html
{%csrf_token%} {{obj.as_p}}
novalidate:HTML5输入类型和浏览器验证
如果表单中包含URLField、EmailField和其他整数字段类似,Django将使用url、email和number这样的HTML5输入类型。默认情况下,浏览器可能会对这些字段进行他们自身的验证,这些验证可能比Django的验证更严格。如果你想禁用这个行为,请设置form标签的novalidate属性,或者制定一个不同的字段,如TextInput。
2、ModelForm基本操作
forms.py
classUserInfoModelForm(forms.ModelForm): classMeta: model=models.UserInfo#与models建立了依赖关系 fields="__all__"
views.py
defindex(request):
ifrequest.method=="GET":
obj=UserInfoModelForm()
returnrender(request,"index.html",{'obj':obj})
elifrequest.method=="POST":
obj=UserInfoModelForm(request.POST)
print(obj.is_valid())#这是方法,别忘记了加括号
print(obj.cleaned_data)
print(obj.errors)
returnrender(request,"index.html",{'obj':obj})
自定制字段名
如何定义http上定义的字段呢,自定义写成中文的?之前的用法是在Form里写上label。ModelForm定义要用verbose_name
models.py
classUserInfo(models.Model): username=models.CharField(max_length=32,verbose_name='用户') email=models.EmailField(verbose_name='邮箱') user_type=models.ForeignKey(to='UserType',to_field='id',verbose_name='类型')
如果不在model里定义,在modelForm里实现,利用labels
classUserInfoModelForm(forms.ModelForm):
classMeta:
model=models.UserInfo
fields="__all__"
labels={
'username':'用户名',
'email':'邮箱',
}
展示指定的列
fields="__all__"#展示所有字段 fields=['username','email']#显示指定列 exclude=['username']#排除指定列
为什么modelForm里也能做验证?
form里面有is_valid,cleaned_data,errors,
#Form验证: UserInfoForm->Form->BaseForm(包含is_valid等方法) #ModelForm验证: UserInfoModelForm->ModelForm->BaseModelForm->BaseForm
3、ModelForm组件
ModelForm
a.classMeta:
model,#对应Model的
fields=None,#字段
exclude=None,#排除字段
labels=None,#提示信息
help_texts=None,#帮助提示信息
widgets=None,#自定义插件
error_messages=None,#自定义错误信息(整体错误信息fromdjango.core.exceptionsimportNON_FIELD_ERRORS)
field_classes=None#自定义字段类(也可以自定义字段)
localized_fields=('birth_date',)#本地化,如:根据不同时区显示数据
如:
数据库中
2016-12-2704:10:57
setting中的配置
TIME_ZONE='Asia/Shanghai'
USE_TZ=True
则显示:
2016-12-2712:10:57
b.验证执行过程
is_valid->full_clean->钩子->整体错误
c.字典字段验证
defclean_字段名(self): #可以抛出异常 #fromdjango.core.exceptionsimportValidationError return"新值"
d.用于验证
model_form_obj=XXOOModelForm() model_form_obj.is_valid() model_form_obj.errors.as_json() model_form_obj.clean() model_form_obj.cleaned_data
e.用于创建
model_form_obj=XXOOModelForm(request.POST) ####页面显示,并提交##### #默认保存多对多 obj=form.save(commit=True) #不做任何操作,内部定义save_m2m(用于保存多对多) obj=form.save(commit=False) obj.save()#保存单表信息 obj.save_m2m()#保存关联多对多信息
f.用于更新和初始化
obj=model.tb.objects.get(id=1) model_form_obj=XXOOModelForm(request.POST,instance=obj) ...
PS:单纯初始化
model_form_obj=XXOOModelForm(initial={...})
注意:导入模块名(fields、widgets)和字段名重复,所以导入时要起个别名。
fromdjangoimportforms
fromdjango.formsimportfieldsasFfields
fromdjango.formsimportwidgetsasFwidgets
classUserInfoModelForm(forms.ModelForm):
is_rmb=Ffields.CharField(widget=Fwidgets.CheckboxInput())
classMeta:
model=models.UserInfo
fields='__all__'
#fields=['username','email']
#exclude=['username']
labels={
'username':'用户名',
'email':'邮箱',
}
help_texts={
'username':'...'
}
widgets={
'username':Fwidgets.Textarea(attrs={'class':'c1'})
}
error_messages={
'__all__':{#整体错误信息
},
'email':{
'required':'邮箱不能为空',
'invalid':'邮箱格式错误..',
}
}
field_classes={#定义字段的类是什么
#'email':Ffields.URLField#这里只能填类,加上括号就是对象了。
}
#localized_fields=('ctime',)#哪些字段做本地化
4、ModelForm数据库操作
4.1、创建数据save
如果数据验证是ok的,那么save,就直接在数据库中创建完数据了
ifobj.is_valid():
obj.save()#创建数据
在如下一对多、多对多关系中:
classUserType(models.Model): caption=models.CharField(max_length=32) classUserGroup(models.Model): name=models.CharField(max_length=32) classUserInfo(models.Model): username=models.CharField(max_length=32) email=models.EmailField() user_type=models.ForeignKey(to='UserType',to_field='id') u2g=models.ManyToManyField(UserGroup)
这样的话,执行上面的obj.save()会在UserInfo表和多对多关系表里都增加数据。
views.py
defindex(request):
ifrequest.method=="GET":
obj=UserInfoModelForm()
returnrender(request,'index.html',{'obj':obj})
elifrequest.method=="POST":
obj=UserInfoModelForm(request.POST)
ifobj.is_valid():
obj.save()#等价以下三句
#instance=obj.save(False)
#instance.save()
#obj.save_m2m()
returnrender(request,'index.html',{'obj':obj})
4.2、save做了哪些操作?
save源码里:
defsave(self,commit=True): """""" ifcommit: self.instance.save()#指的当前model对象 self._save_m2m()#指:保存m2m对象 else: self.save_m2m=self._save_m2m returnself.instance#model类的对象 """"""
所以instance=obj.save(False)时,什么都不会操作。
ifobj.is_valid(): instance=obj.save(False) instance.save()#当前对象表数据创建 obj.save_m2m()#多对多表数据创建 #上面这三句完成的是和上面obj.save一样的操作。拆开就可以自定制操作了
4.3、修改数据
修改表数据是,记得把instance信息也传进去,不然是新建数据,而不是对某行数据进行修改。
编辑用户信息,新url方式保留默认数据
urls.py
url(r'^user_list/',views.user_list),
url(r'^edit-(\d+)/',views.user_edit),
views.py
defuser_list(request):
li=models.UserInfo.objects.all().select_related('user_type')#这里只能是外键,多对多字段也不可以
returnrender(request,'user_list.html',{'li':li})
defuser_edit(request,nid):
#获取当前id对象的用户信息
#显示用户已经存在数据
ifrequest.method=="GET":
user_obj=models.UserInfo.objects.filter(id=nid).first()
mf=UserInfoModelForm(instance=user_obj)#把默认数据传递进去
returnrender(request,'user_edit.html',{'mf':mf,'nid':nid})
elifrequest.method=='POST':
#数据修改的信息,给数据库的哪一行做修改?
user_obj=models.UserInfo.objects.filter(id=nid).first()
mf=UserInfoModelForm(request.POST,instance=user_obj)#指定给谁做修改
ifmf.is_valid():
mf.save()
else:
print(mf.errors.as_json())
returnrender(request,'user_edit.html',{'mf':mf,'nid':nid})
user_list.html
-
{%forrowinli%}
- {{row.username}}-{{row.user_type.caption}}-
编辑
{%endfor%}
user_edit.html
{%csrf_token%} {{mf.as_p}}
5、ModelForm钩子、额外字段
数据验证钩子
从上面的Form和ModelForm中,他们都是继承了BaseForm,而is_valid是在BaseForm中定义的,所以ModelForm也能和Form一样使用各种钩子
额外字段
像网页上的checkbox,一个月内免登陆,用提交到数据库么?这个只需要设置session和cookie就可以了。
views.py
classUserInfoModelForm(forms.ModelForm): is_rmb=fields.CharField(widget=widgets.CheckboxInput())#额外字段 classMeta: model=models.UserInfo fields='__all__'
6、总结
1.生成HTML标签:classMeta:...
2.mf=xxxModelForm(instance=ModelObj)生成默认值
3.额外的标签,is_rmb=Ffields.CharField(widget=Fwidgets.CheckboxInput())
4.各种验证is_valid()->各种钩子...
5.mf.save()
#或 instance=mf.save(False) instance.save() mf.save_m2m()
ModelForm因为model和form耦合太密切,所以一般写小程序用它。
补充知识:Django——rest序列化(自定义serializers)
fromdjango.shortcutsimportrender
fromrest_framework.viewsimportAPIView
fromrest_framework.responseimportResponse
fromrepositoryimportmodels
fromrest_frameworkimportserializers
classMyField(serializers.CharField):
#返回数据到to_respresentation
defget_attribute(self,instance):
teacher_list=instance.teachers.all()
returnteacher_list
#格式化数据
defto_representation(self,value):
ret=[]
forrowinvalue:
ret.append({'id':row.id,'name':row.name})
returnret
classTestSerializer(serializers.ModelSerializer):
#get_attribute,去数据库中获取值
#to_representation,在页面中显示值
#level_name=serializers.CharField(source='get_level_display')#obj.get_level_display
#test_char=serializers.CharField(source='xx.xx.xx')#以.的形式跨表
x1=serializers.SerializerMethodField()
xx=MyField()
classMeta:
model=models.Course
fields=['name','level_name']
defget_x1(self,obj):
pass
在ModelSerializer直接以get_字段的形式
classCouserDetailSerializer(serializers.ModelSerializer):
course_name=serializers.CharField(source='course.name')
recommend_courses_list=serializers.SerializerMethodField()
price_policy_list=serializers.SerializerMethodField()
classMeta:
model=models.CourseDetail
fields=['id','course_name','recommend_courses_list']
defget_recommend_courses_list(self,obj):
ret=[]
course_list=obj.recommend_courses.all()
foritemincourse_list:
ret.append({'id':item.id,'name':item.name})
returnret
defget_price_policy_list(self,obj):
#当前课程所有的价格策略
#ret=[]
#price_policy_list=obj.course.price_policy.all()
#returnret
#ret=[]
#price_policy_list=models.PricePolicy.objects.filter(content_type__app_label='repository',
#content_type__model='course',
#object_id=obj.couser_id)
#returnret
return"ssss"
以上这篇DjangoModelForm操作及验证方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。