1

I want a TabularInline field in Django admin to be required. How do I proceed? Here's my code:

admin.py

class SchoolInline(TabularInline):
    model = School.labs.through
    extra = 1

class LaboratoryAdmin(ModelAdmin):
    inlines = [SchoolInline]

register(Lab, LaboratoryAdmin)

I simplified a lot the problem, but basically that's it. In result I get a drop-down list with all the schools. The problem is that this field isn't required, but I want it to be required. How can I do this the most simple way?

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
user2282405
  • 873
  • 2
  • 9
  • 10
  • 1
    http://stackoverflow.com/questions/1206903/how-do-i-require-an-inline-in-the-django-admin – andrea.ge May 14 '13 at 12:55
  • 1
    Doesn't solve my problem because when I've already got a school added, next time I want to submit the form without adding another school it doesn't submit the form because it checks each time if a new school has been added. – user2282405 May 14 '13 at 14:10
  • OK, then can you define with more details your problem? How many schools do you want to be required? – andrea.ge May 14 '13 at 14:18
  • If you want at least one form in the formset to be required, take a look at: http://wadofstuff.blogspot.com/2009/08/requiring-at-least-one-inline-formset.html. – Brandon Taylor May 14 '13 at 14:59

1 Answers1

4

forms.py

# One form required
from django.core.exceptions import ValidationError
from django.forms.models import BaseInlineFormSet    

class AtLeastOneFormSet(BaseInlineFormSet):
    def clean(self):
        super(AtLeastOneFormSet, self).clean()
        non_empty_forms = 0
        for form in self:
            if form.cleaned_data:
                non_empty_forms += 1
        if non_empty_forms - len(self.deleted_forms) < 1:
            raise ValidationError("Please fill at least one form.")

forms.py

# First form not empty and can not be deleted
from django.forms.models import BaseInlineFormSet    

class RequiredInlineFormSet(BaseInlineFormSet):
    def _construct_form(self, i, **kwargs):
        form = super(RequiredInlineFormSet, self)._construct_form(i, **kwargs)
        if i < 1:
            form.empty_permitted = False
        return form

You also need to change the view and remove the delete button for the first form as shown here: https://docs.djangoproject.com/en/dev/topics/forms/formsets/#manually-rendered-can-delete-and-can-order

admin.py

from django.contrib.admin import TabularInline

class SchoolInline(TabularInline):
    model = School.labs.through
    extra = 1
    formset = RequiredInlineFormSet # or AtLeastOneFormSet
andrea.ge
  • 1,937
  • 1
  • 18
  • 27
  • Already a lot better. But there is still a problem: if I already added 1 or more schools and then, later, delete them all by checking the checkbox "Delete" for each of them, it doesn't raise an error... There should always be at least one school added. How can I solve that? – user2282405 May 15 '13 at 06:32
  • I edited the solution above, could you please test it? Thanks. – andrea.ge May 15 '13 at 09:21
  • Still doesn't work perfectly. Now when I delete a school, even if there is still one resting, it says me that the field is required... – user2282405 May 16 '13 at 09:11
  • I proposed another solution. It should work if your problem can be rephrased as "always having at least one school associated to each laboratory" – andrea.ge May 19 '13 at 16:14