[Django]-Django – Admin – Inline – 'extra' value based on some condition

2πŸ‘

βœ…

Not sure if it would work and I am not too familiar with inlines and this extra attribute, but you could subclass django.contrib.admin.InlineModelAdmin and replace the InlineModelAdmin.extra attribute with a python property:

from django.contrib import admin
from myproject.myapp.models import MyInlineModel

class DynamicExtraInlineModelAdmin(admin.InlineModelAdmin):

    @property
    def extra():
        return 1 if some_logic else 0

admin.site.register(MyInlineModel, DynamicExtraInlineModelAdmin)

6πŸ‘

Just simply override the get_extra method. The following example set extra to 0 for the add view and 10 for the edit view.

class MyInline(admin.TabularInline):
    model = MyModel

    def get_extra(self, request, obj=None, **kwargs):
        return 0 if obj else 10
πŸ‘€Langlyin

3πŸ‘

You can just leverage inheritance..

// based on some condition
kwargs['extra'] = something
.........
return super(*******Inline, self).get_formset(request, obj, **kwargs) // 'defaults.update(kwargs)' takes care of the dynamic overriding 

The get_formset method from my project :

def get_formset(self, request, obj=None, **kwargs):
    ## Put in your condition here and assign extra accordingly
    if obj is None:
        return super(ImageInline, self).get_formset(request, obj, **kwargs)
    current_topic = TopicPage.objects.get(pk = obj.id)
    topic_images = ThruImage.objects.filter(topic = current_topic)

    kwargs['extra'] = 0
    if len(topic_images) <= 3:
        kwargs['extra'] = 3 - len(topic_images)
    return super(ImageInline, self).get_formset(request, obj, **kwargs)

This is of course, useful only for simple conditionals based off the parent model object ..

1πŸ‘

You just monkey patch django’s (1.3.1) source code as follows:

First add the following code to your app:

from django.forms.models import inlineformset_factory
from django.contrib.admin.util import flatten_fieldsets
from django.utils.functional import curry
from django.contrib.admin.options import InlineModelAdmin

class MyInlineModelAdmin(InlineModelAdmin):
    #extra = 1
    def get_formset(self, request, obj=None, **kwargs):
        """Returns a BaseInlineFormSet class for use in admin add/change views."""
        if self.declared_fieldsets:
            fields = flatten_fieldsets(self.declared_fieldsets)
        else:
            fields = None
        if self.exclude is None:
            exclude = []
        else:
            exclude = list(self.exclude)
        exclude.extend(kwargs.get("exclude", []))
        exclude.extend(self.get_readonly_fields(request, obj))
        # if exclude is an empty list we use None, since that's the actual
        # default
        exclude = exclude or None
        if obj and hasattr(obj, 'id'): # <<=======================================
            _extra = 0
        else:
            _extra = self.extra
        defaults = {
            "form": self.form,
            "formset": self.formset,
            "fk_name": self.fk_name,
            "fields": fields,
            "exclude": exclude,
            "formfield_callback": curry(self.formfield_for_dbfield, request=request),
            "extra": _extra,
            "max_num": self.max_num,
            "can_delete": self.can_delete,
        }
        defaults.update(kwargs)
        return inlineformset_factory(self.parent_model, self.model, **defaults)

class MyTabularInline(MyInlineModelAdmin):
    template = 'admin/edit_inline/tabular.html'

and assuming your models are something like:

class ContainerModel(models.Model):
    pass #etc...

class ListModel(models.Model):
    pass #etc...

then change your admins to:

class ListModelInline(MyTabularInline): # <<=================================
    model = MyModel

class ContainerModelAdmin(admin.ModelAdmin):
    inlines = (ListModelInline,)

admin.site.register(ContainerModel, ContainerModelAdmin)
#etc...
πŸ‘€Rabih Kodeih

Leave a comment