Django admin inlines - minimum number of forms
Asked Answered
M

5

8

When creating custom model admin inlines in Django, you can set two parameters extra and max_num: the number of additional forms to display, and the maximum number of objects to allow the user to attach to the parent object.

I have a Question model, each of which can have several answers, which are inlines in the Question admin. Most questions will have three answers, so I would like to show three inlines by default; however, when editing a question that already has three answers, it looks crowded and tacky to show three whole extra fields when most likely there aren't going to be any more answers at all. What I want is essentially a min_num parameter: I want to show at least three fields by default, empty if there are less than three answers already, while still allowing the user to add more than that which will then all be shown.

I've found tickets for adding this both to formsets and inlines, but it looks like they haven't been resolved. Is there any convenient way to do this in Django 1.4 currently?

Mulley answered 2/10, 2012 at 15:30 Comment(0)
C
2

There is a patch available for this:

https://code.djangoproject.com/ticket/17642

Cash answered 27/12, 2012 at 22:23 Comment(1)
Looks like it's been merged, and is now available in Django 1.7! \o/Savate
B
10

I had to set extra and min_num for this to work

class MyInline(admin.TabularInline):
    extra = 0
    min_num = 3
Battery answered 7/1, 2018 at 4:31 Comment(1)
When I do this, I get "This field is required" errors on every field of every empty formset. In my case I want to show 3 forms, but 0 are required.Alpert
C
2

There is a patch available for this:

https://code.djangoproject.com/ticket/17642

Cash answered 27/12, 2012 at 22:23 Comment(1)
Looks like it's been merged, and is now available in Django 1.7! \o/Savate
A
2

I ended up using a dynamic extra value:

class AnswerInline(admin.TabularInline):
    model = Answer
    initial_num = 3

    def get_extra(self, request, obj=None, **kwargs):
        if obj is not None:
            return max(self.initial_num - obj.answers.count(), 1)
        return self.initial_num

This ensures there are either 3 forms, or one more than the number of populated forms, and doesn't run into the validation issue that min_num has.

Alpert answered 27/2, 2018 at 4:49 Comment(0)
L
1

I'm not sure. But in my project I do this. Count of filled forms = count(not deleted existing) + count(changed and not deleted new). In clean method we are sure that all the forms are validated already (and not contain blank forms).

forms.py:

class AnswersFormsetBase(forms.models.BaseInlineFormSet):
    def clean(self):
        super(AnswersFormsetBase, self).clean()

        initial_num = len(filter(lambda f: not self._should_delete_form(f), self.initial_forms))
        extra_num = len(filter(lambda f: f.has_changed() and not self._should_delete_form(f), self.extra_forms))
        if initial_num + extra_num < 2:
            raise ValidationError("Polling should be at least two possible answers")

AnswerFormset = inlineformset_factory(Polling, Answer, formset=AnswersFormsetBase)

admin.py:

class AnswersInline(admin.TabularInline):
    model = Answer
    fk_name = "polling"
    formset = AnswerFormset # from forms.py

class PollingModelAdmin(admin.ModelAdmin):
    inlines = [AnswersInline]

admin.site.register(Polling, PollingModelAdmin)
Ledford answered 27/11, 2012 at 17:24 Comment(0)
H
-1

set max_num to 3 and comment extra, by this you will always have 3 lines in add and change form.

Houseclean answered 10/7, 2014 at 7:6 Comment(1)
Question doesn't seem to specify that 3 is the max, just the usual.Alpert

© 2022 - 2024 — McMap. All rights reserved.