modelForm 组件
概念
将数据库与form 组件结合用起来的中间插件
与 form 组件的区别
form组件的难处:
form 可以实现 对数据的验证以及 form 的表单标签的生成
但是她做不到一点就是无法将数据库串联起来,无法做到数据的传回
比如编辑页面的时候无法拿到当前正要被编辑的值
modelfom 组件在 form组件的基础上进行升级 :
自动创建 form 类 (将model类 转换成 form类)
在 from类手动创建的是时候就可以发现,form 的创建和 model 的数据库几乎完全一致
而modelform 可以帮我们直接实现这个操作而不在需要手动创建
直接和 model 对应上,对于 model 的增删改查会更加的简单便捷
创建关联
用form 组件的形式创建
class Book(models.Model): title=models.CharField(max_length=32) price=models.DecimalField(max_digits=8,decimal_places=2) # 999999.99 date=models.DateField() publish=models.ForeignKey("Publish") authors=models.ManyToManyField("Author") class BookForm(forms.Form): title = forms.CharField(max_length=32,label="书籍名称") price = forms.DecimalField(max_digits=8, decimal_places=2,label="价格") # 999999.99 date = forms.DateField( label="日期", widget=widgets.TextInput(attrs={"type":"date"}) ) publish=forms.ModelChoiceField(queryset=Publish.objects.all()) authors=forms.ModelMultipleChoiceField(queryset=Author.objects.all())
用modelform 组件的形式创建
class BookForm(ModelForm): class Meta: model=Book # 制定要被转换的表 fields="__all__" # 控制要被转换的字段 , __all__ 表示所有字段 ,除了 用 __all__ 的时候对多个字段使用的时候用列表的形式 # fields=["title","price"] # 除了 用 __all__ 的时候用字符串形式,对多个字段使用的时候用列表的形式
常见仓鼠:
from django.forms import ModelForm #在视图函数中,定义一个类,比如就叫StudentList,这个类要继承ModelForm,在这个类中再写一个原类Meta(规定写法,并注意首字母是大写的) #在这个原类中,有以下属性(部分): class StudentList(ModelForm): class Meta: # 对应的Model中的类 model =Student # 注意这里千万别加 "," 会识别成元组导致报错 # 字段,如果是__all__,就是表示列出所有的字段 fields = "__all__" # fields = ["name","age"] # 指定显示某些字段 # 排除的字段 # exclude = ["name","age"] exclude = none# error_messages 错误信息
# 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS) error_messages = { '__all__':{}, # 整体的错误信息放在这里 'name':{'required':"用户名不能为空",}, # 个别字段的错误信息单独显示 'age':{'required':"年龄不能为空",}, }
# widgets 用法,比如把输入用户名的input框给为Textarea# 首先得导入模块 from django.forms import widgets as wid #因为重名,所以起个别名 widgets = { # 这个widgets只是一个参数名,不要搞混 "name":wid.Textarea(attrs={"class":"c1"}) #还可以自定义属性 } # labels 自定义在前端显示的名字 labels= { "name":"用户名" } # help_texts 显示帮助信息 help_texts={ "name":"这里写你的名字" }
# field_classes 自定义字段类 field_classes={ 'email':fields.URLField #这里只能填类,不能加括号,加上括号就变成对象了。
# 这是把邮箱的默认邮箱类自定义成url类了。 }
ps:
在没有用 form 以及 modelform 之前, 这两个本质都是一样,都是保存的就是字符串而已,其实是没有意义的
只有 form 以及 modelform 才可以对他们进行校验,在这时候 UUIDField , EmailField 之类的才有意义
因为只有 form 以及 modelform 才可以将 models.xxxx 转换成 forms.xxx 的时候进行自己的 is_vaild 方法进行相关的校验
name = models.CharField
name = models.UUIDField name = models.URLField name = models.EmailField name = models.IPAddressField
数据传回
和 form 组件的对比
如果不用ModelForm,对于要显示原来的数据,需要挨个取一遍值,
如果ModelForm,只需要加一个 instance=obj(obj是要修改的数据库的一条数据的对象)就可以得到同样的效果
对当前编辑的对象的数据的取回,在form 组件的时候是无法操作的
form 类在实例化对象的时候无法接受参数
modelform 组件可以 以instance参数接受一个对象
save 的使用
对于数据的编辑更新和新建,modelform 类统一使用 .save() 方法
当 当前的 modelform 对象中没有 instance参数的时候默认添加一个新对象
当 当前的 modelform 对象中有 instance参数的时候会按照参数的中的对象进行更新操作
(不给对象参数的话怎么知道要编辑哪一个呢?)
def addbook(request): if request.method == "POST": form = BookForm(request.POST) if form.is_valid(): form.save() # form.model.objects.create(request.POST)
return redirect("/books/") else: return render(request, "add.html", locals()) form=BookForm() return render(request, "add.html", locals()) def editbook(request, edit_book_id): # 被编辑的书的对象 edit_book = Book.objects.filter(pk=edit_book_id).first() if request.method == "POST": form = BookForm(request.POST, instance=edit_book) if form.is_valid(): form.save() # edit_book.update(request.POST)
return redirect("/books/") form=BookForm(instance=edit_book) return render(request, "edit.html",locals())
ModelForm的验证
用form方法的时候,验证功能的函数其实是写在BaseForm里的:UserInfoForm-->继承了Form--->继承了BaseForm(is_valid......)
点击提交的时候,modelform也可以做验证。UserInfoModelForm-->继承了ModelForm--->继承了BaseModelForm--->继承了BaseForm(is_valid......)
UserInfoModelForm下面也应该有obj.is_valid(), obj.cleaned_data, obj.errors 等方法。
ModelForm 做验证的时候与Form方法是一样的。
我们可以像使用Form类一样自定义局部钩子方法和全局钩子方法来实现自定义的校验规则。
如果我们不重写具体字段并设置validators属性的话,ModelForm是按照模型中字段的validators来校验的。
总结
modelform 组件在 form 组件的基础上,保留了 form 组件的全部功能
而且 更加简单的实现了与model 表的映射创建
并且新增了与model 表的链接得以可以对当前操作的对象直接操作
知识点整合
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 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={...})
# 你看不见我,
其实我有偷偷藏起来一份更加详细的博客 就在这里了。。。读书人的事情