I have a Museum
which has a ForeignKey to a Town
, which in turn has a ForeignKey to a Country
. In fact Museum
also has a ForeignKey to Country
, which allows me to get hold of all of the Museums
as inlines in the Country
admin view, which is where I need to be able to edit them.
# models.py
class Country(models.Model):
...
class Town(models.Model):
country = models.ForeignKey(Country, on_delete=models.CASCADE)
class Museum(models.Model):
town = models.ForeignKey(Town, on_delete=models.CASCADE)
# admin.py
class MuseumAdminInline(admin.TabularInline):
model = Museum
class CountryAdmin(admin.ModelAdmin):
model = Country
inlines = [MuseumAdminInline]
So far so straightforward. But, I don’t just want a long list of Museums
in the Country
admin, pumped out by the {% for inline_admin_form in inline_admin_formset %}
in admin/edit_inline/tabular.html.
Instead I want to do the equivalent of {% regroup museums by city as city_list %}
with the inline_admin_formset
, regrouping the inline_admin_form
of Musems
by City
.
I’ll need to point MuseumAdminInline.template
at a customised version of tabular.html
.
But I am a bit unclear what else I need to do and how. It seems to me that I need to be able to customise the view and the formset factory that creates the formset. Is that correct? I am not sure which components of the chain I should be targeting.
(Eventually I will also want to make some fields of City
available for each group, but I think that once I have a handle on the basic proposition I’ll understand better how to achieve that.)
Thanks for any help.
You might want to look at some packages like django-nested-inline · PyPI or django-nested-admin · PyPI
Even if they don’t quite do exactly what you want to do, reading the source code for them may give you some ideas or a direction for further research.
Actually I started with those, but I think it’s going to be cleaner and more sustainable to hardcode the customisation. I feel I am missing the big picture of what’s required, to be able to make better sense of what those packages are doing.
Oops, I missed the part in your text description where you identified that Museum
has foreign keys to both Country
and Town
. (Admittedly, I was paying more attention to the code snippet of the model.)
<conjecture>
This being the case, I believe you could sort the instances of Museum
by Town
, by using the ordering
attribute of the AdminInline
class.
e.g.
class MuseumAdminInline(admin.TabularInline):
model = Museum
ordering = ['town__name']
(assuming that Town
has a name
attribute you wish to use)
</conjecture>
(Warning, I’m winging this - try this at your own risk.)
Indeed so, already ordered that way at the model level - but I want some much more forceful regrouping into a hierarchy of items.
I’m not sure I’m understanding what you mean by this.
What I think you’re saying is that you want something that (very loosely) is going to resemble this:
Country:
country_field_1
country_field_2
country_field_3
Museums:
Town 1:
Museum 1:
museum_field_1
museum_field_2
museum_field_3
Museum 2:
museum_field_1
museum_field_2
museum_field_3
Town 2:
Museum 3:
museum_field_1
museum_field_2
museum_field_3
Museum 4:
museum_field_1
museum_field_2
museum_field_3
And so what you have are a visual separation of the Museum
entries, even though they all reside in the one formset.
Am I close? (If not, then I’m not following you.)
<conjecture>
If I’m correct here, then I think this can be accomplished with a custom tabular.html
template as you identified at top.
My first attempt would be to use the {% ifchanged
tag in the
{% for inline_admin_form in inline_admin_formset %}
loop to create the div
under which the related Museum
forms would be indented.
So I might end up with something like:
{% for inline_admin_form in inline_admin_formset %}
{% ifchanged inline_admin_form.instance.town.name %}
<h3>inline_admin_form.instance.town.name</h3>
<div>
{% endifchanged %}
... (all the stuff currently in the existing template)
{% ifchanged inline_admin_form.instance.town.name %}
</div>
{% endifchanged %}
</conjecture>
(Note, if you have blank forms associated with this, then there is probably more work needing to be done to handle those appropriately.)
Thanks - yes, that is essentially what I need to do.
I think I am getting somewhere with this. {% ifchanged %}
is a cunning idea. Meanwhile I have also worked out how to get hold of the formset as it comes out of the factory, and if I can add additional attributes to it, that will give me another level of control.