Reputation: 831
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?
Upvotes: 8
Views: 7258
Reputation: 2667
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.
Upvotes: 2
Reputation: 1319
I had to set extra and min_num for this to work
class MyInline(admin.TabularInline):
extra = 0
min_num = 3
Upvotes: 10
Reputation: 1086
set max_num to 3 and comment extra, by this you will always have 3 lines in add and change form.
Upvotes: -1
Reputation: 3329
There is a patch available for this:
https://code.djangoproject.com/ticket/17642
Upvotes: 2
Reputation: 41
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)
Upvotes: 1