Python学习笔记Day25 - Django_ModelForm
目录
ModelForm
model和form的结合体,比form方便,但是耦合太强,不适合大规模
参考博客
Model + Form => 验证 + 数据库操作
# 利用model.A中的字段,不用重复再写字段
创建ModelForm
from django import forms
from django.forms import widgets as Fwidgets
class UserInfoModelForm(forms.ModelForm):
is_rmb = Ffields.CharField(widget=Fwidgets.CheckboxInput()) # 创建model以外的标签,用法同form的Field
class Meta: # 创建model已有的字段标签
model = models.UserInfo
fields = '__all__'
def clean_username(self):
old = self.cleaned_data['username']
return old
./views.py
obj = XXOOModelForm(request.POST) # 提交数据
if obj.is_valid():
obj = form.save() # 默认自动保存多对多数据
else:
print(obj.errors['user'][0]) # 获取指定错误信息
print(obj.errors.as_json()) # 打包为字典的错误信息
./xxx.html
<p>{{ obj.user }} {{ obj.user.errors }}</p>
{{ obj.as_p }} {{ obj.user.errors }} # 一次性以<p>生成所有标签
{{ obj.as_ul }} {{ obj.user.errors }} # 一次性以<ul>生成所有标签
<table>
{{ obj.as_table }} {{ obj.user.errors }} # 一次性以<table>生成所有标签
</table>
{{ form.xxoo.label }} # label值
{{ form.xxoo.id_for_label }} # label的for值,id_xxx
{{ form.xxoo.label_tag }} # 自动生成label(包含上述两点)
{{ form.xxoo.errors }} # 错误信息
Meta字段
class Meta: # 生成HTML标签
model = models.UserInfo -> 对应的Model
fields=None -> 字段, '__all__' => 所有字段, ['username','email']
exclude=None -> 排除字段, ['username']
labels=None -> 提示信息, {'username':'用户名'}
help_texts=None -> 帮助提示信息, {'username':'用户名不能以数字开头...'}
widgets=None -> 自定义插件, {'username':F_widgets...}
=> 需要从Form里导入widgets并 as ...重命名,以免和字段名重复
error_messages=None -> 自定义错误信息, {'username':{'required':'不能为空'},'email':{...}}
=> 可整体定义错误信息 {'__all__':{...}}
# ? from django.core.exceptions import NON_FIELD_ERRORS
field_classes=None -> 自定义字段类型 (将model中定义的字段类型修改)
=> {'email':F_field.URLField}
localized_fields=None -> 本地化,如:根据不同时区显示数据, =('birth_date',)
# 如:
数据库中,默认UTC时间
2016-12-27 04:10:57
需要在setting中做相应的配置
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = True
则显示:
2016-12-27 12:10:57
article_modelform = ArticleModelForm(label_suffix='') -> 修改label后缀
创建或修改数据
.../views.py
obj = XXOOModelForm() # 页面显示
模板文件中的使用类似Form
obj = XXOOModelForm(request.POST) # 提交数据
if obj.is_valid():
obj = form.save() # 默认自动保存多对多数据
values = obj.cleaned_data # 获取正确数据
return ...
else:
print(obj.errors.as_json())
return ...
# 拆分为三步
obj = form.save(commit=False)
obj.save() # 保存单表信息
obj.save_m2m() # 保存关联的多对多信息
更新和初始化数据
-
修改数据GET时,传入原始数据
obj = model.tb.objects.get(id=1) # 从model中获取对象 model_form_obj = XXOOModelForm(instance=obj) # GET时,将obj对象作为默认值传给modelFrom显示
-
修改完POST时,将数据更新至当前对象,否则将新建数据而不是更新数据
obj = model.tb.objects.get(id=1) model_form_obj = XXOOModelForm(request.POST,instance=obj) # POST时,将提交的数据更新至obj对象
PS: 单纯初始化
model_form_obj = XXOOModelForm(initial={...})
修改样式属性
-
第一种方法:
class BookForm(forms.ModelForm): class Meta: ... widgets = { 'name': Textarea(attrs={'cols': 80, 'rows': 20}), 'description': Textarea(attrs={'cols': 80, 'rows': 20}), }
-
第二种重写__init__方法:
class BookForm(forms.ModelForm): class Meta: model = Book def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['name'].widget.attrs.update({'class': 'special'}) self.fields['description'].widget.attrs.update(size='40')
验证的执行过程
*UserForm* >>继承>> *Form* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>继承>> *BaseForm*(is_valid...)
*UserModelForm* >>继承>> *ModelForm* >>继承>> *BaseModelForm* >>继承>> *BaseForm*
ModelForm验证的使用方法与Form一样
is_valid -> full_clean -> 钩子 -> 整体错误
字典字段验证
def clean_字段名(self):
# 可以抛出异常
# from django.core.exceptions import ValidationError
return "新值"
用于验证
obj = XXOOModelForm()
obj.is_valid()
obj.errors.as_json()
obj.clean()
obj.cleaned_data
Django ModelChoiceField前台下拉菜单显示object的解决方法
在model中添加如下代码即可,不加的话显示就是object
def __str__(self):
return self.name
隐藏的modelform标签,而如果该标签为required,提交时浏览器会报错
解决办法:
-
form表单添加novalidate属性,但会导致所有验证都不能用,不建议
-
取消该标签的required