Alasdair
Alasdair

Reputation: 308909

Limit Django's inlineformset_factory to only create new objects

I am using django's inline formset factory. To use the example in the docs,

author = Author.objects.get(pk=1)
BookFormSet = inlineformset_factory(Author, Book)
formset = BookFormSet(request.POST, instance=author)

will create an inline formset to edit books by a particular author.

I want to create a formset that only allows users to add new books by that author, not edit existing books. Is there a simple way to use inlineformset_factory to do this?

Upvotes: 11

Views: 3935

Answers (3)

Andre Miras
Andre Miras

Reputation: 3840

Based on Jeremy Lewis and if you don't want to subclass BaseInlineFormSet, you can just give an empty queryset parameter to your BookFormSet.

See pseudo (untested) Django 1.6 code sample:

BookFormSet = inlineformset_factory(parent=Author, model=Book)
if request.method == "POST":
    formset = BookFormSet(request.POST, request.FILES, instance=author)
    if formset.is_valid():
        formset.save()
else:
    queryset = Book.objects.none() # does not allow to edit books
    formset = BookFormSet(instance=project, initial=initial, queryset=queryset)
return render(request, "add_book.html", { "formset": formset, })

Upvotes: 3

user268157
user268157

Reputation:

Actually the answer is given in the documentation. Just don't give any instance to the FormSet. From the doc:

>>> from django.forms.models import inlineformset_factory
>>> BookFormSet = inlineformset_factory(Author, Book)
>>> author = Author.objects.get(name=u'Mike Royko')
>>> formset = BookFormSet() # This will create an empty form with your model fields

You can then create view as follows:

if request.method == "POST":
    formset = BookFormSet(request.POST, request.FILES)
    if formset.is_valid():
        formset.save()
else:
    formset = BookFormSet()
return render_to_response("add_book.html", {
    "formset": formset,

Hope it helps.

Upvotes: 0

Jeremy Lewis
Jeremy Lewis

Reputation: 1719

inlineformset_factory takes a formset kwarg, which defaults to BaseInlineFormSet. BaseInlineFormSet subclasses BaseModelFormSet, which defines a get_queryset method. If you create a BaseInlineFormSet subclass and override get_queryset to return EmptyQuerySet(), you should get what you're after. In the above example then, it would look like this:

from django.db.models.query import EmptyQuerySet
from django.forms.models import BaseInlineFormSet

class BaseInlineAddOnlyFormSet(BaseInlineFormSet):
    def get_queryset(self):
        return EmptyQuerySet()

author = Author.objects.get(pk=1)
BookFormSet = inlineformset_factory(Author, Book, formset=BaseInlineAddOnlyFormSet)
formset = BookFormSet(request.POST, instance=author)

Upvotes: 9

Related Questions