从模型构造表单

模型表单

class ModelForm

如果你正开发数据库驱动程序,那么你的表单就会和Django模型映射结合得很紧密。举个例子,你可能有一个 BlogComment 对象,也希望创建一个表单,好让用户提交评论。在这个例子里,你可能会重复定义表单字段,因为有些字段已经在模型里定义过了。

所以,Django提供了一个帮助类,来帮你从Django模型创建 表单

例子:

>>> from django.forms import ModelForm

# Create the form class.
>>> class ArticleForm(ModelForm):
...     class Meta:
...         model = Article

# 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)

字段类型

生成的 表单 中的字段,都会对应到模型的各个字段上。每个模型字段对有其对应的默认表单字段。例如,模型中的一个 CharField 字段,将生成为表单中的 CharField 。模型中的 ManyToManyField 字段,将生成为表单中的``多选字段`` 。以下是对应表格:

模型字段 表单字段
自生成字段(AutoField) 不会在表单中显示
BigIntegerField IntegerField with min_value set to -9223372036854775808 and max_value set to 9223372036854775807.
BooleanField BooleanField
CharField CharField with max_length set to the model field’s max_length
CommaSeparatedIntegerField CharField
DateField DateField
DateTimeField DateTimeField
DecimalField DecimalField
EmailField EmailField
FileField FileField
FilePathField CharField
FloatField FloatField
ForeignKey ModelChoiceField (see below)
ImageField ImageField
IntegerField IntegerField
IPAddressField IPAddressField
GenericIPAddressField GenericIPAddressField
ManyToManyField ModelMultipleChoiceField (see below)
NullBooleanField CharField
PhoneNumberField USPhoneNumberField (from django.contrib.localflavor.us)
PositiveIntegerField IntegerField
PositiveSmallIntegerField IntegerField
SlugField SlugField
SmallIntegerField IntegerField
TextField CharField with widget=forms.Textarea
TimeField TimeField
URLField URLField with verify_exists set to the model field’s verify_exists
New in Django 1.2: BigIntegerField 是在Django 1.2版中新增的。

在你的模型中,可能会有像 外键(ForeignKey)ManyToManyFiel 这样的特殊情况:

  • 外键字段(ForeignKey 将使用 django.forms.ModelChoiceField 呈现,其中的 ChoiceField 的来源是模型的 QuerySet
  • ManyToManyField 将使用 django.forms.ModelMultipleChoiceField 呈现,其中的 MultipleChoiceField 的来源是模型的 QuerySet

此外,各种生成的表单字段将有以下这些属性设置:

  • 如果在模型中设置 blank=True ,那么生成的表单字段中 required 将设置为 False 。反之亦然。
  • 如果在模型中设置了 verbose_name ,那么生成的表单字段的首字母将会大写呈现。
  • 模型中的 help_text 将对应表单字段中的 help_text
  • 如果模型字段中有 choices ,那么表单字段的 widget 将被设置为 Select ,其中的选项将会从模型字段中的 choices 而来。这个选项将默认选中一个空白项。如果该字段为必填字段,将会让用户必选该项。如果模型字段中设置了 blank=False 同时设置了 default 值,那么这个 default 值将会被默认选中。

最后,要注意,你随时可以重写模型字段所对应的表单字段。参阅下面的 重写默认的组件或字段类型

完整示例

定义这样的模型:

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 __unicode__(self):
        return self.name

class Book(models.Model):
    name = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)

class AuthorForm(ModelForm):
    class Meta:
        model = Author

class BookForm(ModelForm):
    class Meta:
        model = Book

依照这些模型,上面的 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())

is_valid() 方法和 errors

当你第一次调用 ModelFormis_valid() 方法或访问 errors 属性, 这将会触发表单的验证:ref:model validation<validating-objects>`。 这会对把你的模型传到 ``ModelForm` 的构造方法时产生副作用。 譬如,当你调用 is_valid() 方法,表单就会把所有日期字段转换为date对象。

save() 方法

每个使用 ModelForm 开发表单时,都会有 save() 方法。 这个方法会把绑定的表单数据创建及保存到数据库中。 每个 ModelForm 对象,都可以通过关键字 instance 来访问模型实体, 如果已经有了实体,那么 save() 方法将会更新这个实体。 如果没有实体,那么 save() 将创建一个实体:

# 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.
>>> a = Article.objects.get(pk=1)
>>> f = ArticleForm(instance=a)
>>> 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()

注意, 如果表单中的数据没能通过验证, save() 方法将引发 ValueError

save() 方法还接受一个可选参数 commit ,可接受 TrueFalse 值。 如果调用使用 commit=False 调用 save() 方法,那么这个返回值其实还没保存到数据库中。 这时,你就可以通过 save() 来获取模型实例了。 如果你希望在保存之前做些操作或者你希望使用 model saving options ,这将非常有用。 commit 的默认值是 True

当你的模型和别的模型有多对多关系时,使用 commit=False 将有些副作用。 当你保存表单时,设置 commit=False ,Django将不会马上保存这个多对多的关系。 那是因为无法在没有实体时保存对应的多对多数据。

要解决这个问题,每次你使用 commit=False 保存表单时,Django都会添加一个 save_m2m() 到你的 ModelForm 子类中。 在你手动保存了实体后,你可以调用 save_m2m() 方法去保存你的多对多数据。 例子:

# Create a form instance with POST data.
>>> f = AuthorForm(request.POST)

# Create, but don't save the new author instance.
>>> new_author = f.save(commit=False)

# Modify the author in some way.
>>> new_author.some_field = 'some_value'

# Save the new instance.
>>> new_author.save()

# Now, save the many-to-many data for the form.
>>> f.save_m2m()

save_m2m() 仅需你使用 save(commit=False) 时调用。 当你在表单上只简单地调用 save() ,所有的数据,包括多对多关系数据,就不需要再调用其它方法了。 例子:

# Create a form instance with POST data.
>>> a = Author()
>>> f = AuthorForm(request.POST, instance=a)

# Create and save the new author instance. There's no need to do anything else.
>>> new_author = f.save()

除了 save()save_m2m() 方法, ModelFormforms 表单的其它调用方式完全一样。 例如, is_valid() 方法就是用来校验的, is_multipart() 方法用来决定上传的文件是否需要分块( request.FILES 就必须传给表单),诸如此类。 参阅 binding-uploaded-files 获取更多信息。

在表单中使用字段的子集

在一些情况下,你可能不希望把模型中的所有字段都生成到表单中。这里有三种方法告诉 ModelForm 只使用模型字段的子集:

1.设置模型中的字段为 editable=False 。那么,所有通过 ModelForm 生成的表单,都不会有这个字段出现了。

2.设置 ModelForm 中内置类 Metafields 属性。如果有需要,你可以设置为需要在表单中显示的字段名称的列表。表单将按顺序显示列表中的字段。

3.设置 ModelForm 中内置类 Metaexclude 属性。如果有需要,表单将不会显示你给的字段名称列表中的表单字段。

例如,如果你想做一个 Author 模型的表单(上面定义的那个),只需要包括 nametitle 字段,你像这样可以设置 fieldsexclude

class PartialAuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ('name', 'title')

class PartialAuthorForm(ModelForm):
    class Meta:
        model = Author
        exclude = ('birth_date',)

Author只包括三个字段,’name’, ‘title’, 和’birth_date’,上面的表单将包括完全一致的字段。

Note

如果你在构造 ModelForm 表单时设置了 fieldsexclude ,那么在你调用 save() 方法时,那些字段将不会被设置到表单中。同样的,如果你手动把字段添加到表单中,它们也不会跟随模型进行初始化。

Django会阻止保存未完成的模型,所以,如果模型中含有非空字段,而又不提供默认值,那么调用 ModelFormsave() 将会失败。为了避免这些错误,你必须初始化这些非空字段:

author = Author(title='Mr')
form = PartialAuthorForm(request.POST, instance=author)
form.save()

又或者,你可以使用 save(commit=False) 然后设置这些非空字段:

form = PartialAuthorForm(request.POST)
author = form.save(commit=False)
author.title = 'Mr'
author.save()

查阅 section on saving forms _获取更多关于 save(commit=False) 使用方法的咨询。

重写默认的组件或字段类型

New in Django 1.2: widgets 属性是Django 1.2新增的。

默认的字段类型,在上面的 Field types 表中已经描述过了。如果你的模型中有一个 DateField 字段,那么表单中就会出现一个 DateField 字段。但 ModelForm 也提供一种自适应的方式改变模型字段所对应的组件类型及字段类型。

To specify a custom widget for a field, use the widgets attribute of the inner Meta class. This should be a dictionary mapping field names to widget classes or instances.

For example, if you want the a CharField for the name attribute of Author to be represented by a <textarea> instead of its default <input type="text">, you can override the field’s widget:

from django.forms import ModelForm, Textarea

class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ('name', 'title', 'birth_date')
        widgets = {
            'name': Textarea(attrs={'cols': 80, 'rows': 20}),
        }

The widgets dictionary accepts either widget instances (e.g., Textarea(...)) or classes (e.g., Textarea).

If you want to further customize a field – including its type, label, etc. – you can do this by declaratively specifying fields like you would in a regular Form. Declared fields will override the default ones generated by using the model attribute.

For example, if you wanted to use MyDateFormField for the pub_date field, you could do the following:

class ArticleForm(ModelForm):
    pub_date = MyDateFormField()

    class Meta:
        model = Article

If you want to override a field’s default label, then specify the label parameter when declaring the form field:

>>> class ArticleForm(ModelForm):
...     pub_date = DateField(label='Publication date')
...
...     class Meta:
...         model = Article

Note

If you explicitly instantiate a form field like this, Django assumes that you want to completely define its behavior; therefore, default attributes (such as max_length or required) are not drawn from the corresponding model. If you want to maintain the behavior specified in the model, you must set the relevant arguments explicitly when declaring the form field.

For example, if the Article model looks like this:

class Article(models.Model):
    headline = models.CharField(max_length=200, null=True, blank=True,
                                help_text="Use puns liberally")
    content = models.TextField()

and you want to do some custom validation for headline, while keeping the blank and help_text values as specified, you might define ArticleForm like this:

class ArticleForm(ModelForm):
    headline = MyFormField(max_length=200, required=False,
                           help_text="Use puns liberally")

    class Meta:
        model = Article

See the form field documentation for more information on fields and their arguments.

Changing the order of fields

By default, a ModelForm will render fields in the same order that they are defined on the model, with ManyToManyField instances appearing last. If you want to change the order in which fields are rendered, you can use the fields attribute on the Meta class.

The fields attribute defines the subset of model fields that will be rendered, and the order in which they will be rendered. For example given this model:

class Book(models.Model):
    author = models.ForeignKey(Author)
    title = models.CharField(max_length=100)

the author field would be rendered first. If we wanted the title field to be rendered first, we could specify the following ModelForm:

>>> class BookForm(ModelForm):
...     class Meta:
...         model = Book
...         fields = ('title', 'author')

Overriding the clean() method

You can override the clean() method on a model form to provide additional validation in the same way you can on a normal form.

In this regard, model forms have two specific characteristics when compared to forms:

By default the clean() method validates the uniqueness of fields that are marked as unique, unique_together or unique_for_date|month|year on the model. Therefore, if you would like to override the clean() method and maintain the default validation, you must call the parent class’s clean() method.

Also, a model form instance bound to a model object will contain a self.instance attribute that gives model form methods access to that specific model instance.

Form inheritance

As with basic forms, you can extend and reuse ModelForms by inheriting them. This is useful if you need to declare extra fields or extra methods on a parent class for use in a number of forms derived from models. For example, using the previous ArticleForm class:

>>> class EnhancedArticleForm(ArticleForm):
...     def clean_pub_date(self):
...         ...

This creates a form that behaves identically to ArticleForm, except there’s some extra validation and cleaning for the pub_date field.

You can also subclass the parent’s Meta inner class if you want to change the Meta.fields or Meta.excludes lists:

>>> class RestrictedArticleForm(EnhancedArticleForm):
...     class Meta(ArticleForm.Meta):
...         exclude = ('body',)

This adds the extra method from the EnhancedArticleForm and modifies the original ArticleForm.Meta to remove one field.

There are a couple of things to note, however.

  • Normal Python name resolution rules apply. If you have multiple base classes that declare a Meta inner class, only the first one will be used. This means the child’s Meta, if it exists, otherwise the Meta of the first parent, etc.
  • For technical reasons, a subclass cannot inherit from both a ModelForm and a Form simultaneously.

Chances are these notes won’t affect you unless you’re trying to do something tricky with subclassing.

Interaction with model validation

As part of its validation process, ModelForm will call the clean() method of each field on your model that has a corresponding field on your form. If you have excluded any model fields, validation will not be run on those fields. See the form validation documentation for more on how field cleaning and validation work. Also, your model’s clean() method will be called before any uniqueness checks are made. See Validating objects for more information on the model’s clean() hook.

Model formsets

Like regular formsets, Django provides a couple of enhanced formset classes that make it easy to work with Django models. Let’s reuse the Author model from above:

>>> from django.forms.models import modelformset_factory
>>> AuthorFormSet = modelformset_factory(Author)

This will create a formset that is capable of working with the data associated with the Author model. It works just like a regular formset:

>>> formset = AuthorFormSet()
>>> print formset
<input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" />
<tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /></td></tr>
<tr><th><label for="id_form-0-title">Title:</label></th><td><select name="form-0-title" id="id_form-0-title">
<option value="" selected="selected">---------</option>
<option value="MR">Mr.</option>
<option value="MRS">Mrs.</option>
<option value="MS">Ms.</option>
</select></td></tr>
<tr><th><label for="id_form-0-birth_date">Birth date:</label></th><td><input type="text" name="form-0-birth_date" id="id_form-0-birth_date" /><input type="hidden" name="form-0-id" id="id_form-0-id" /></td></tr>

Note

modelformset_factory uses formset_factory to generate formsets. This means that a model formset is just an extension of a basic formset that knows how to interact with a particular model.

Changing the queryset

By default, when you create a formset from a model, the formset will use a queryset that includes all objects in the model (e.g., Author.objects.all()). You can override this behavior by using the queryset argument:

>>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))

Alternatively, you can create a subclass that sets self.queryset in __init__:

from django.forms.models import BaseModelFormSet

class BaseAuthorFormSet(BaseModelFormSet):
    def __init__(self, *args, **kwargs):
        super(BaseAuthorFormSet, self).__init__(*args, **kwargs)
        self.queryset = Author.objects.filter(name__startswith='O')

Then, pass your BaseAuthorFormSet class to the factory function:

>>> AuthorFormSet = modelformset_factory(Author, formset=BaseAuthorFormSet)

If you want to return a formset that doesn’t include any pre-existing instances of the model, you can specify an empty QuerySet:

>>> AuthorFormSet(queryset=Author.objects.none())

Controlling which fields are used with fields and exclude

By default, a model formset uses all fields in the model that are not marked with editable=False. However, this can be overridden at the formset level:

>>> AuthorFormSet = modelformset_factory(Author, fields=('name', 'title'))

Using fields restricts the formset to use only the given fields. Alternatively, you can take an “opt-out” approach, specifying which fields to exclude:

>>> AuthorFormSet = modelformset_factory(Author, exclude=('birth_date',))

Providing initial values

New in Django 1.4: Please see the release notes

As with regular formsets, it’s possible to specify initial data for forms in the formset by specifying an initial parameter when instantiating the model formset class returned by modelformset_factory. However, with model formsets, the initial values only apply to extra forms, those that aren’t bound to an existing object instance.

Saving objects in the formset

As with a ModelForm, you can save the data as a model object. This is done with the formset’s save() method:

# Create a formset instance with POST data.
>>> formset = AuthorFormSet(request.POST)

# Assuming all is valid, save the data.
>>> instances = formset.save()

The save() method returns the instances that have been saved to the database. If a given instance’s data didn’t change in the bound data, the instance won’t be saved to the database and won’t be included in the return value ( instances , in the above example).

When fields are missing from the form (for example because they have been excluded), these fields will not be set by the save() method. You can find more information about this restriction, which also holds for regular ModelForms, in 在表单中使用字段的子集.

Pass commit=False to return the unsaved model instances:

# don't save to the database
>>> instances = formset.save(commit=False)
>>> for instance in instances:
...     # do something with instance
...     instance.save()

This gives you the ability to attach data to the instances before saving them to the database. If your formset contains a ManyToManyField, you’ll also need to call formset.save_m2m() to ensure the many-to-many relationships are saved properly.

Limiting the number of editable objects

Changed in Django 1.2: Please see the release notes

As with regular formsets, you can use the max_num and extra parameters to modelformset_factory to limit the number of extra forms displayed.

max_num does not prevent existing objects from being displayed:

>>> Author.objects.order_by('name')
[<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>]

>>> AuthorFormSet = modelformset_factory(Author, max_num=1)
>>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
>>> [x.name for x in formset.get_queryset()]
[u'Charles Baudelaire', u'Paul Verlaine', u'Walt Whitman']

If the value of max_num is greater than the number of existing related objects, up to extra additional blank forms will be added to the formset, so long as the total number of forms does not exceed max_num:

>>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=2)
>>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
>>> for form in formset:
...     print form.as_table()
<tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" value="Charles Baudelaire" maxlength="100" /><input type="hidden" name="form-0-id" value="1" id="id_form-0-id" /></td></tr>
<tr><th><label for="id_form-1-name">Name:</label></th><td><input id="id_form-1-name" type="text" name="form-1-name" value="Paul Verlaine" maxlength="100" /><input type="hidden" name="form-1-id" value="3" id="id_form-1-id" /></td></tr>
<tr><th><label for="id_form-2-name">Name:</label></th><td><input id="id_form-2-name" type="text" name="form-2-name" value="Walt Whitman" maxlength="100" /><input type="hidden" name="form-2-id" value="2" id="id_form-2-id" /></td></tr>
<tr><th><label for="id_form-3-name">Name:</label></th><td><input id="id_form-3-name" type="text" name="form-3-name" maxlength="100" /><input type="hidden" name="form-3-id" id="id_form-3-id" /></td></tr>
Changed in Django 1.2: Please see the release notes

A max_num value of None (the default) puts no limit on the number of forms displayed.

Using a model formset in a view

Model formsets are very similar to formsets. Let’s say we want to present a formset to edit Author model instances:

def manage_authors(request):
    AuthorFormSet = modelformset_factory(Author)
    if request.method == 'POST':
        formset = AuthorFormSet(request.POST, request.FILES)
        if formset.is_valid():
            formset.save()
            # do something.
    else:
        formset = AuthorFormSet()
    return render_to_response("manage_authors.html", {
        "formset": formset,
    })

As you can see, the view logic of a model formset isn’t drastically different than that of a “normal” formset. The only difference is that we call formset.save() to save the data into the database. (This was described above, in Saving objects in the formset.)

Overiding clean() on a model_formset

Just like with ModelForms, by default the clean() method of a model_formset will validate that none of the items in the formset violate the unique constraints on your model (either unique, unique_together or unique_for_date|month|year). If you want to override the clean() method on a model_formset and maintain this validation, you must call the parent class’s clean method:

class MyModelFormSet(BaseModelFormSet):
    def clean(self):
        super(MyModelFormSet, self).clean()
        # example custom validation across forms in the formset:
        for form in self.forms:
            # your custom formset validation

Using a custom queryset

As stated earlier, you can override the default queryset used by the model formset:

def manage_authors(request):
    AuthorFormSet = modelformset_factory(Author)
    if request.method == "POST":
        formset = AuthorFormSet(request.POST, request.FILES,
                                queryset=Author.objects.filter(name__startswith='O'))
        if formset.is_valid():
            formset.save()
            # Do something.
    else:
        formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
    return render_to_response("manage_authors.html", {
        "formset": formset,
    })

Note that we pass the queryset argument in both the POST and GET cases in this example.

Using the formset in the template

There are three ways to render a formset in a Django template.

First, you can let the formset do most of the work:

<form method="post" action="">
    {{ formset }}
</form>

Second, you can manually render the formset, but let the form deal with itself:

<form method="post" action="">
    {{ formset.management_form }}
    {% for form in formset %}
        {{ form }}
    {% endfor %}
</form>

When you manually render the forms yourself, be sure to render the management form as shown above. See the management form documentation.

Third, you can manually render each field:

<form method="post" action="">
    {{ formset.management_form }}
    {% for form in formset %}
        {% for field in form %}
            {{ field.label_tag }}: {{ field }}
        {% endfor %}
    {% endfor %}
</form>

If you opt to use this third method and you don’t iterate over the fields with a {% for %} loop, you’ll need to render the primary key field. For example, if you were rendering the name and age fields of a model:

<form method="post" action="">
    {{ formset.management_form }}
    {% for form in formset %}
        {{ form.id }}
        <ul>
            <li>{{ form.name }}</li>
            <li>{{ form.age }}</li>
        </ul>
    {% endfor %}
</form>

Notice how we need to explicitly render {{ form.id }}. This ensures that the model formset, in the POST case, will work correctly. (This example assumes a primary key named id. If you’ve explicitly defined your own primary key that isn’t called id, make sure it gets rendered.)

Inline formsets

Inline formsets is a small abstraction layer on top of model formsets. These simplify the case of working with related objects via a foreign key. Suppose you have these two models:

class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    author = models.ForeignKey(Author)
    title = models.CharField(max_length=100)

If you want to create a formset that allows you to edit books belonging to a particular author, you could do this:

>>> from django.forms.models import inlineformset_factory
>>> BookFormSet = inlineformset_factory(Author, Book)
>>> author = Author.objects.get(name=u'Mike Royko')
>>> formset = BookFormSet(instance=author)

Note

inlineformset_factory uses modelformset_factory and marks can_delete=True.

More than one foreign key to the same model

If your model contains more than one foreign key to the same model, you’ll need to resolve the ambiguity manually using fk_name. For example, consider the following model:

class Friendship(models.Model):
    from_friend = models.ForeignKey(Friend)
    to_friend = models.ForeignKey(Friend)
    length_in_months = models.IntegerField()

To resolve this, you can use fk_name to inlineformset_factory:

>>> FriendshipFormSet = inlineformset_factory(Friend, Friendship, fk_name="from_friend")

Using an inline formset in a view

You may want to provide a view that allows a user to edit the related objects of a model. Here’s how you can do that:

def manage_books(request, author_id):
    author = Author.objects.get(pk=author_id)
    BookInlineFormSet = inlineformset_factory(Author, Book)
    if request.method == "POST":
        formset = BookInlineFormSet(request.POST, request.FILES, instance=author)
        if formset.is_valid():
            formset.save()
            # Do something.
    else:
        formset = BookInlineFormSet(instance=author)
    return render_to_response("manage_books.html", {
        "formset": formset,
    })

Notice how we pass instance in both the POST and GET cases.

comments powered by Disqus