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={...})

浙公网安备 33010602011771号