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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。