day23-ModelForm组件
一、前言
之前我们学习了modelform的基本使用,下面我们就来完整的学习一下modelform的组件,以及验证,还有一个用户详细信息的小例子。
二、ModleForm组件
说明:上一篇博客我们说了modle,fields,和exclude,接下来我们把其他的也练习完毕
ModelForm a. class Meta: model, # 对应Model的 fields=None, # 字段 exclude=None, # 排除字段 labels=None, # 提示信息 help_texts=None, # 帮助提示信息 widgets=None, # 自定义插件 error_messages=None, # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS) field_classes=None # 自定义字段类 (也可以自定义字段) localized_fields=('birth_date',) # 本地化,如:根据不同时区显示数据 如: 数据库中 2016-12-27 04:10:57 setting中的配置 TIME_ZONE = 'Asia/Shanghai' USE_TZ = True 则显示: 2016-12-27 12:10:57
1、labels=None
说明:提示信息,以下的关键字都是按照labels写的,但是为了方便,就不写class UserInfoModelForm和class Meta了,而且每一个字段之间是没有逗号的
class UserInfoModelForm(forms.ModelForm): class Meta: model = models.UserInfo fields = "__all__" #提示信息 labels = { 'username':'用户名', 'email':'邮箱', }
如图:
2、help_texts=None
说明:输出输入框的帮助信息
#输出帮助信息 help_texts = { 'username':'....', 'email':'xxx@126.com', }
如图:
3、Html插件
from django.forms import widgets as Fwidgets #需要导入html插件,并且需要重新命名,因为跟关键字重复了 #html插件 widgets = { "username":Fwidgets.Textarea(attrs={'class':'c1'}) #加上属性 }
如图:
4、error_messages
说明:错误提示
error_messages = { "__all__":{ #定义整体的错误信息 }, 'email':{ 'required':'邮箱不为空', # 根据required是code值 'invalid':"邮箱格式错误" } }
5、fields_classes
说明:把标签的格式转换为其他格式,这边需要导入fields,但是需要重新起一个别名不然会跟自身的fields冲突,就会报错
from django.forms import fields as Ffields #导入fields,并且取一个别名 field_classes = { 'email':Ffields.URLField #把email格式转换为url格式 }
6、localized_fields=('birth_date',)
说明:表示都有哪些字段做本地话
localized_fields=('birth_date',) 如: 数据库中 2016-12-27 04:10:57 setting中的配置 TIME_ZONE = 'Asia/Shanghai' USE_TZ = True 则显示: 2016-12-27 12:10:57
7、自定义字段
说明:modelform可以自定义一些字段,比如10天免登录,这个东西不需要提交到后台的
class UserInfoModelForm(forms.ModelForm): #自定义字段 is_rmb = Ffields.CharField( widget=Fwidgets.CheckboxInput() #modelform可以自定义一些字段,比如10天免登录,这个东西不需要提交给后台的 ) class Meta: model = models.UserInfo fields = "__all__"
三、modelform保存数据
3.1、ForeignKey
说明:1对1的外键,是只要你验证通过了,只要save一下,数据就直接保存在数据库了
def index(request): if request.method == "GET": obj = UserInfoModelForm() return render(request,'index.html',{'obj':obj}) elif request.method == "POST": obj = UserInfoModelForm(request.POST) if obj.is_valid(): obj.save() #验证成功之后,是直接保存在数据库中 # print(obj.is_valid()) # print(obj.cleaned_data) # print(obj.errors.as_json()) return render(request,'index.html',{'obj':obj})
3.2、ManyToMany
说明:多对多也是一样的,只要save了,我们先来一个多对多的models设置
class UserType(models.Model): caption = models.CharField(max_length=32) class UserGroup(models.Model): name = models.CharField(max_length=32) class UserInfo(models.Model): username = models.CharField(max_length=32) email = models.EmailField() user_type = models.ForeignKey(to="UserType",to_field='id',on_delete=models.CASCADE) u2g = models.ManyToManyField(UserGroup) #跟上面的UserGroup建立多对多关系
但是如果我们写上什么呐,写上obj.save(Fales),写上这一句的时候,说明都不帮你做,代码如下:
def index(request): if request.method == "GET": obj = UserInfoModelForm() return render(request,'index.html',{'obj':obj}) elif request.method == "POST": obj = UserInfoModelForm(request.POST) if obj.is_valid(): instance = obj.save(commit=False) #写上这一句的时候,什么都不帮你做 instance.save() #这个不等于obj.save(),它只保存当前这个数据,不会帮你保存many_to_many obj.save_m2m() #上面三句的效果,跟之前的obj.save(commit=True)效果是一样的 return render(request,'index.html',{'obj':obj})
四、modelForm实现的小例子
数据库的表关系,就是上面的多对多的关系,这个我就不多说了,我们就直接进入正题吧
4.1、用户列表
1、路由url
from django.urls import path from app01.views import accounts urlpatterns = [ path('index/', accounts.index), ]
2、user_list函数
from app01 import models def user_list(request): li = models.UserInfo.objects.all().select_related('user_type') #select_related 只能是外键,不能是多对多 return render(request,'user_list.html',{'li':li})
3、user_list.html模板
<body> <ul> {% for row in li %} <li>{{ row.username }}-{{ row.user_type.caption }}-<a href="/edit-{{ row.id }}/">编辑</a></li> {% endfor %} </ul> </body>
4.2、用户编辑页面
1、路由url
from django.urls import re_path from app01.views import accounts urlpatterns = [ re_path(r'^edit-(\d+)/', accounts.user_list), ]
2、user_edit函数
def user_edit(request,nid): if request.method == "GET": user_obj = models.UserInfo.objects.filter(id=nid).first() mf = UserInfoModelForm(instance=user_obj) #把对象传进来,在前端就能显示默认值 return render(request,'user_edit.html',{'mf':mf,'nid':nid}) elif request.method == "POST": user_obj = models.UserInfo.objects.filter(id=nid).first() mf = UserInfoModelForm(request.POST,instance=user_obj) #我把数据提交过来了,并且我拿到对哪个对象进行更新数据 if mf.is_valid(): mf.save() else: print(mf.errors.as_json()) return render(request,'user_edit.html',{'mf':mf,'nid':nid})
3、user_edit.html模板
<body> <form method="post" action="/edit-{{ nid }}/"> {{ mf.as_p }} <input type="submit" value="提交"/> </form> </body>
五、验证补充
因为ModelForm最终继承是BaseForm,所以他跟From是同一个老祖宗,所以他们的验证方式是一样的,以及隐藏的钩子都是一模一样的,所以补充如下:
b. 验证执行过程 is_valid -> full_clean -> 钩子 -> 整体错误 c. 字典字段验证 def clean_字段名(self): # 可以抛出异常 # from django.core.exceptions import ValidationError 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={...})