Reputation: 7740
Is it possible to dynamically set the 'extra' option in the Django Admin Inline?
For example, If Student class have Address class as Inline. If there is no Address inline's associated with Student, then extra =1. If there is any Address inline's associated with Student, then extra =0.
Upvotes: 3
Views: 4308
Reputation: 156
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
Upvotes: 7
Reputation: 71
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 ..
Upvotes: 3
Reputation: 9521
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...
Upvotes: 1
Reputation: 19998
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)
Upvotes: 2