Search code examples
pythonpython-3.xdjangodjango-admininline

How do I make a TabularInline required in Django admin?


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?


Solution

  • 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