Creating forms from models从模型创建表单
ModelForm
class ModelForm[source]
如果您正在构建一个数据库驱动的应用程序,那么可能会有一些形式与Django模型紧密相连。 例如,您可能有一个BlogComment
model
,并且您想创建一个可以让用户提交注释的表单。 在这种情况下,在forms.py
中定义字段类型是多余的,因为您已经定义了模型中的字段。
因此,Django提供了一个帮助类,可以让您从Djangomodel
创建一个Form类。
例如:
>>> from django.forms import ModelForm
>>> from myapp.models import Article
# Create the form class.
>>> class ArticleForm(ModelForm):
... class Meta:
... model = Article
... fields = ['pub_date', 'headline', 'content', 'reporter']
# Creating a form to add an article.
>>> form = ArticleForm()
# Creating a form to change an existing article.
>>> article = Article.objects.get(pk=1)
>>> form = ArticleForm(instance=article)
Field types字段类型
生成的Form
类将按照fields
属性中指定的顺序为每个指定的模型字段创建一个表单域。
每个模型字段都有相应的默认表单域。 例如,模型上的CharField
在表单上表示为CharField
。ManyToManyField
模型被表示为MultipleChoiceField
。 以下是完整的转化列表:
正如您所期望的,ForeignKey
和ManyToManyField
模型字段类型是特殊情况:
ForeignKey
由django.forms.ModelChoiceField
表示,它是一个ChoiceField
,其选项是ModelSet
模型。
ManyToManyField
由django.forms.ModelMultipleChoiceField
表示,它是一个MultipleChoiceField
,其选项是ModelSet
模型。
另外,每个生成的表单域都具有如下属性:
如果模型字段为blank= True
,则表单字段中的必填项设置为False。否则,required = True
。
表单字段的标签设置为模型字段的verbose_name
,第一个字符大写。
表单字段的help_text
设置为model
字段的help_text
。
如果模型字段有选择集,则表单域的小部件将被设置为选择,选择来自模型字段的选择。选择通常包括默认选择的空白选项。如果需要该字段,则强制用户进行选择。如果模型字段具有blank= True
和显式默认值(将初始选择默认值),则不会包括空白选项。
最后,请注意,您可以覆盖用于给定模型字段的表单字段。请参阅覆盖下面的默认字段。
A full example一个完整的例子
考虑这套模型:
from django.db import models
from django.forms import ModelForm
TITLE_CHOICES = (
('MR', 'Mr.'),
('MRS', 'Mrs.'),
('MS', 'Ms.'),
)
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choices=TITLE_CHOICES)
birth_date = models.DateField(blank=True, null=True)
def __str__(self): # __unicode__ on Python 2
return self.name
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ['name', 'title', 'birth_date']
class BookForm(ModelForm):
class Meta:
model = Book
fields = ['name', 'authors']
使用这些模型,上面的ModelForm
子类将大致相当于此(唯一的区别是save()
方法,我们稍后将讨论)。
from django import forms
class AuthorForm(forms.Form):
name = forms.CharField(max_length=100)
title = forms.CharField(
max_length=3,
widget=forms.Select(choices=TITLE_CHOICES),
)
birth_date = forms.DateField(required=False)
class BookForm(forms.Form):
name = forms.CharField(max_length=100)
authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
Validation on a ModelForm对ModelForm的验证
验证ModelForm
有两个主要步骤:
- 验证表单
- 验证模型实例
就像正常的表单验证一样,当调用is_valid()
或访问errors
属性并在调用full_clean()
时明确地触发模型窗体验证,尽管通常不会在实践中使用后一种方法。
模型验证(Model.full_clean()
)从窗体的clean()
方法调用之后,从窗体验证步骤触发。
警告
清理过程以各种方式修改传递给
ModelForm
构造函数的模型实例。 例如,模型上的任何日期字段都将转换为实际的日期对象。失败的验证可能使底层模型实例处于不一致的状态,因此不建议重用它。
覆盖clean()
方法
您可以覆盖模型窗体上的clean()方法,以与正常形式相同的方式提供其他验证。
连接到模型对象的模型窗体实例将包含一个实例属性,该属性允许其方法访问该特定模型实例。
警告
ModelForm.clean()
方法设置一个标志,使模型验证步骤验证标记为unique
,unique_together
或unique_for_date| month | year
的模型字段的唯一性。如果要覆盖
clean()
方法并保持此验证,则必须调用父类的clean()
方法。
与模型验证的交互
作为验证过程的一部分,ModelForm
将调用您的模型上每个字段的clean()
方法,该表单上有相应的字段。 如果您排除了任何模型字段,则不会在这些字段上运行验证。 有关现场清理和验证如何工作的更多信息,请参阅表单验证文档。
在进行任何唯一性检查之前,将调用该模型的clean()
方法。 有关模型的clean()
钩子的更多信息,请参阅验证对象。
关于模型的error_messages
的注意事项
在表单域级别或元数据级别定义的错误消息始终优先于模型字段级别定义的错误消息。
仅在模型验证步骤中引发ValidationError
时,才会使用模型字段上定义的错误消息,并且在表单级别没有定义相应的错误消息。
您可以通过将NON_FIELD_ERRORS
键添加到ModelForm
内部Meta
类的error_messages
字典中来覆盖模型验证引发的NON_FIELD_ERRORS
中的错误消息:
from django.forms import ModelForm
from django.core.exceptions import NON_FIELD_ERRORS
class ArticleForm(ModelForm):
class Meta:
error_messages = {
NON_FIELD_ERRORS: {
'unique_together': "%(model_name)s's %(field_labels)s are not unique.",
}
}
The save()
method
Every ModelForm also has a save() method. This method creates and saves a database object from the data bound to the form. A subclass of ModelForm can accept an existing model instance as the keyword argument instance; if this is supplied, save() will update that instance. If it’s not supplied, save() will create a new instance of the specified model:
>>> from myapp.models import Article
>>> from myapp.forms import ArticleForm
# Create a form instance from POST data.
>>> f = ArticleForm(request.POST)
# Save a new Article object from the form's data.
>>> new_article = f.save()
# Create a form to edit an existing Article, but use
# POST data to populate the form.
>>> a = Article.objects.get(pk=1)
>>> f = ArticleForm(request.POST, instance=a)
>>> f.save()