Django之modelform组件
modelform来源:
构建一个数据库驱动的应用,那么你可能会有与Django的模型紧密映射的表单。比如,你有个Student模型,并且你还想创建一个表单让大家提交评论到这个模型中。在这种情况下,写一个forms.Form类,然后在表单类中定义字段,这种一般创建表单的做法是冗余的,因为你已经在ORM模型model中定义了字段的属性和功能,完全没必要重新写一遍字段。
一、核心用法
基于这个原因,Django提供一个辅助类帮助我们利用Django的ORM模型model创建Form。
用法的核心是: 1.首先从django.forms导入ModelForm; 2.编写一个自己的类,继承ModelForm; 3.在新类里,设置元类Meta; 4.在Meta中,设置model属性为你要关联的ORM模型,这里是Article; 5.在Meta中,设置fields属性为你要在表单中使用的字段列表; 6.列表里的值,应该是ORM模型model中的字段名。 上面的例子中,因为model和form比较简单,字段数量少,看不出这么做的威力和效率。但如果是那种大型项目,每个模型的字段数量几十上百,这么做的收益将非常巨大,而且后面还有一招提高效率的大杀器,也就是一步保存数据的操作。
Django在设计model字段和表单字段时存在大量的相似和重复之处。
特别注意:ManyToManyField和 ForeignKey字段类型属于特殊情况:
-
ForeignKey被映射成为表单类的django.forms.ModelChoiceField,它的选项是一个模型的QuerySet,也就是可以选择的对象的列表,但是只能选择一个。
-
ManyToManyField被映射成为表单类的django.forms.ModelMultipleChoiceField,它的选项也是一个模型的QuerySet,也就是可以选择的对象的列表,但是可以同时选择多个,多对多嘛。
同时,在表单属性设置上,还有下面的映射关系:
如果模型字段设置blank=True,那么表单字段的required设置为False。 否则,required=True。 表单字段的label属性根据模型字段的verbose_name属性设置,并将第一个字母大写。 如果模型的某个字段设置了editable=False属性,那么它表单类中将不会出现该字段。道理很简单,都不能编辑了,还放在表单里提交什么? 表单字段的help_text设置为模型字段的help_text。 如果模型字段设置了choices参数,那么表单字段的widget属性将设置成Select框,其选项来自模型字段的choices。 选单中通常会包含一个空选项,并且作为默认选择。如果该字段是必选的,它会强制用户选择一个选项。 如果模型字段具有default参数,则不会添加空选项到选单中。
以下是使用modelform的示例,详细看代码:
models:
from django.db import models # Create your models here. class Book(models.Model): id = models.AutoField(primary_key=True) #可不填,Django会自动帮你写 title = models.CharField(max_length=32,) price = models.DecimalField(max_digits=5, decimal_places=2,) pub_date = models.DateField() #与Publish(id)建立一对多的外键关系 publish = models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE) # 不会添加外键,会另外创建表格 authors = models.ManyToManyField(to="Author") def __str__(self): return self.title class Meta: verbose_name="书籍" class Publish(models.Model): name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name class Meta: verbose_name="出版社" class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() authorDetail = models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE) def __str__(self): return self.name class Meta: verbose_name = "作者" class AuthorDetail(models.Model): birthday = models.DateField() phone = models.BigIntegerField() addr = models.CharField(max_length=64) def __str__(self): return self.addr class Meta: verbose_name = "作者详情" class user_info(models.Model): name = models.CharField(max_length=64) password = models.CharField(max_length=64) def __str__(self): return self.name
views:
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError from django.forms import widgets as wid from django import forms class BookModelForm(forms.ModelForm): class Meta: model = models.Book #绑定对应的模型 # fields=["title","price"] # exclude = ["title"] fields = "__all__" #自定义要展示的字段 widgets = { #自定义字段的样式 "title": wid.TextInput(attrs={"class": "form-control"}), "price": wid.TextInput(attrs={"class": "form-control"}), "pub_date":wid.TextInput(attrs={"class": "form-control"}), "publish": wid.Select(attrs={"class": "form-control"}), "authors": wid.SelectMultiple(attrs={"class": "form-control"}), } error_messages = { "title": {"required": "该字段不能为空"} #自定义错误信息 } labels = { "title": "书籍名称" #自定义字段名称,展示起来比较素福 } # def clean_title(self): val = self.cleaned_data.get("title") if val.startswith("a"): return val else: raise ValidationError("必须以a开头!") def addbook(request): if request.method == "POST": form = BookModelForm(request.POST) if form.is_valid(): form.save() return redirect("/books/") else: return render(request, 'addbook.html', locals()) else: form = BookModelForm() # modelforms组件 return render(request, 'addbook.html', locals())
html:
<div class="row"> <div class="col-md-4 col-md-offset-3"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="title">{{ field.label }}</label> {{ field }} <span>{{ field.errors.0 }}</span> </div> {% endfor %} <input type="submit"value="submit" class="btn btn-default pull-right"> </form> </div> </div>
详细可参考:http://www.liujiangblog.com/course/django/156
或有关BaseModelform的相关参数可参考:https://blog.csdn.net/russell_tao/article/details/52777302