一:什么是ModelForm呢?
Model + Form ==> ModelForm。model和form的结合体,所以有以下功能:
- 数据验证
- 数据库操作
model有操作数据库的字段,form验证也有那几个字段,虽然耦合度降低,但是代码是有重复的。如果利用model里的字段,那是不是form里的字段就不用写了。
二:下面是一个简单是例子:
from django.db import models class CustomerInfo(models.Model): """客户表""" name = models.CharField(max_length=64) contact_type_choices = ((0,'QQ'),(1,'微信'),(2,'手机')) contact_type = models.SmallIntegerField(choices=contact_type_choices) contact = models.CharField(max_length=64,unique=True,verbose_name="联系方式") source_choices = ((0,'QQ群'),(1,'51CTO'),(2,'百度推广'),(3,'知乎'),(4,'转介绍'),(5,'其它')) source = models.SmallIntegerField(choices=source_choices,verbose_name="客户来源") referral_from = models.ForeignKey("self",blank=True,null=True,verbose_name="转介绍",on_delete=models.CASCADE) consult_courses = models.ManyToManyField("Course",verbose_name="咨询课程") consult_content = models.TextField(verbose_name="咨询内容") status_choices = ((0, '未报名'), (1, '已报名'), (2, '已退学')) status = models.SmallIntegerField(choices=status_choices,verbose_name="状态") consultant = models.ForeignKey("UserProfile",verbose_name="课程顾问",on_delete=models.CASCADE) date = models.DateField(auto_now_add=True) def __str__(self): return self.name
from django.forms import ModelForm from crm import models from django import forms class CustomerForm(ModelForm): class Meta: model = models.CustomerInfo fields = '__all__' exclude = ['consult_content', 'status', 'consult_courses'] readonly_fields = ['contact_type','contact','consultant','referral_from','source'] #并不是真正的设置可读模式,而是用于自定制 def __new__(cls, *args, **kwargs): # cls 就是实例(self) for field_name in cls.base_fields: field_obj = cls.base_fields[field_name] field_obj.widget.attrs.update({'class':'form-control'}) if field_name in cls.Meta.readonly_fields: field_obj.widget.attrs.update({'disabled':'true'}) # print(cls.Meta) # print(cls.Meta.exclude) return ModelForm.__new__(cls) def clean(self): """对数据进行验证,此方法需要在form.is_valid()后才能生效""" # print("cleaned_dtat:", self.cleaned_data) if self.errors: # 表单级别的错误 raise forms.ValidationError(("Please fix errors before re-submit.")) for field in self.Meta.readonly_fields: old_field_val = getattr(self.instance,field) new_form_val = self.cleaned_data[field] if old_field_val != new_form_val: self.add_error(field,"Readonly Field: field should be '{value}' ,not '{new_value}' ". format(**{'value':old_field_val,'new_value':new_form_val}))
def enrollment(request,enrollment_id): """②学员确认信息""" customer_form = forms.CustomerForm(instance=enrollment_obj.customer) if request.method == "POST": customer_form = forms.CustomerForm(instance=enrollment_obj.customer,data=request.POST) if customer_form.is_valid(): customer_form.save() return HttpResponse('合同正在审核中,请等候...') return render(request,'crm/enrollment.html',locals())
注意我们如何在POST和GET情况下传递实例(instance)。
三、Meta的作用:
- ModelForm 通过 Meta 把 db.Field 自动转化为 forms.Field,其中涉及到几步转化
- validators 不变
- 添加 widget 属性,即前端的渲染方式
- 修改 Model 包含的字段,通过 fields 来拿指定字段或者通过 exclude 来排除指定字段
- 修改错误信息
class Meta: 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',)