I'm trying to figure out a way to display the following RelativeInline only if Person.is_member is True.
Current admin.py:
class RelativeInline(admin.TabularInline):
model = Relative
fk_name = 'member'
class PersonAdmin(admin.ModelAdmin):
inlines = [RelativeInline,]
ordering = ('first_name',)
list_filter = ('is_member',)
search_fields = ('first_name', 'last_name',)
date_hierarchy = 'member_date'
list_display = ('first_name', 'last_name', 'is_member', 'member_date', 'photo')
admin.site.register(Person, PersonAdmin)
The only hint I've been able to find is that I might be able to override get_formset, but I couldn't find a good example, so my feeble attempt didn't work.
Here's my failed attempt:
class RelativeInline(admin.TabularInline):
model = Relative
fk_name = 'member'
class PersonAdmin(admin.ModelAdmin):
ordering = ('first_name',)
list_filter = ('is_member',)
search_fields = ('first_name', 'last_name',)
date_hierarchy = 'member_date'
list_display = ('first_name', 'last_name', 'is_member', 'member_date', 'photo')
def get_formset(self, request, obj=None, **kwargs):
if obj.is_member:
inlines = [RelativeInline,]
return super(PersonAdmin, self).get_formset(request, obj, **kwargs)
admin.site.register(Person, PersonAdmin)
There are no errors generated by this code, but no inline appears regardless of whether or not Person.is_member is True or False.
Update: A friend suggested I try changing:
inlines = [RelativeInline,]
to:
self.inlines = [RelativeInline,]
but to no avail. I also tried:
PersonAdmin.inlines = [RelativeInline,]
but the result was the same -- no error, no inline.
Your original solution was pretty close. If you look in django/contrib/admin/options.py around line 290 you'll see that the inline classes are instantiated when the model admin is instantiated, after which the inlines
list is ignored. So setting this list later on in get_formsets() has no effect.
However, you're correct that get_formsets() is the thing to override in order to make your inlines conditional. The inline instances are contained in self.inline_instances
, so to disable them based on the object (e.g. say I want to hide a specific inline on the "add" form) you'd override it like:
class MyAdmin(models.ModelAdmin):
inlines = [MyInline, SomeOtherInline]
def get_formsets(self, request, obj=None):
for inline in self.inline_instances:
if isinstance(inline, MyInline) and obj is None:
continue
yield inline.get_formset(request, obj)
I decided to change the whole paradigm and solve my problem a different way. Instead of having a single admin for all Persons with a conditional inline, I decided to:
In the end, I think this is a cleaner approach. Now Members can be maintained, and relatives (non-members) can be added in the inline. The NonMemberAdmin allows for editing non-members.
models.py:
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
is_member = models.BooleanField()
is_active = models.BooleanField(default=True)
class Meta:
verbose_name_plural = 'Members'
ordering = ('first_name', 'last_name')
class PersonProxy(Person):
class Meta:
proxy = True
verbose_name_plural = 'Non-Members'
class Relationship(models.Model):
name = models.CharField(max_length=50)
class Relative(models.Model):
member = models.ForeignKey(Person, related_name='relative_member')
relative = models.ForeignKey(Person, related_name='relative_relative')
relationship = models.ForeignKey(Relationship)
admin.py:
class RelativeInline(admin.TabularInline):
model = Relative
fk_name = 'member'
class MemberAdmin(admin.ModelAdmin):
inlines = [RelativeInline,]
ordering = ('first_name',)
# list_filter = ('is_member',)
search_fields = ('first_name', 'last_name',)
# date_hierarchy = 'member_date'
list_display = ('first_name', 'last_name', 'member_date')
def queryset(self, request):
return (super(MemberAdmin, self).queryset(request)
.filter(is_member=True, is_active=True))
class NonMemberAdmin(admin.ModelAdmin):
ordering = ('first_name',)
search_fields = ('first_name', 'last_name',)
list_display = ('first_name', 'last_name')
def queryset(self, request):
return (super(NonMemberAdmin, self).queryset(request)
.filter(is_member=False, is_active=True))
admin.site.register(Person, MemberAdmin)
admin.site.register(PersonProxy, NonMemberAdmin)
I realize this question's a bit old and the codebase has changed a bit; there's a cleaner point to override things at now: get_inline_instances
. You can do this:
class PersonAdmin(models.ModelAdmin):
inlines = [RelativeInline,]
def get_inline_instances(self, request, obj=None):
to_return = super(MyAdmin, self).get_inline_instances(request, obj)
#filter out the RelativeInlines if obj.is_member is false
if not obj or not obj.is_member:
to_return = [x for x in to_return if not isinstance(x,RelativeInline)]
return to_return
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With