17

In the same way you can add 'classes': ['collapse'] to one of your ModelAdmin fieldsets, I'd like to be able to have an Inline Model Admin be collapsible.

This ticket, Collapse in admin interface for inline related objects, discusses exactly what I want to accomplish. But in the mean time, what's the best work around while we wait for the next release?

FYI: I've come up with a solution, but I think a better one exists. I'll let the voting take care of it.

Daniel Rhoden
  • 5,977
  • 6
  • 23
  • 28

8 Answers8

5

You can use grappelli - which supports collapsing fieldsets. It uses a solution much like the solutions mentioned above, but the javascript / coding is already done - you just have to add 'classes':(collapse closed',), to your fieldset ( see http://readthedocs.org/docs/django-grappelli/en/latest/customization.html)

for example:

class ModelOptions(admin.ModelAdmin):
    fieldsets = (
        ('', {
            'fields': ('title', 'subtitle', 'slug', 'pub_date', 'status',),
        }),
        ('Flags', {
            'classes': ('grp-collapse grp-closed',),
            'fields' : ('flag_front', 'flag_sticky', 'flag_allow_comments', 'flag_comments_closed',),
        }),
        ('Tags', {
            'classes': ('grp-collapse grp-open',),
            'fields' : ('tags',),
        }),
    )

class StackedItemInline(admin.StackedInline):
    classes = ('grp-collapse grp-open',)

class TabularItemInline(admin.TabularInline):
    classes = ('grp-collapse grp-open',)
maazza
  • 6,198
  • 15
  • 54
  • 91
danbgray
  • 582
  • 3
  • 8
4

I came up with this solution using jQuery that works on TabularInline

var selector = "h2:contains('TITLE_OF_INLINE_BLOCK')";
$(selector).parent().addClass("collapsed");
$(selector).append(" (<a class=\"collapse-toggle\" id=\"customcollapser\" href=\"#\"> Show </a>)");
$("#customcollapser").click(function() {
    $(selector).parent().toggleClass("collapsed");
});
gerdemb
  • 10,547
  • 15
  • 62
  • 71
4

In modern-day Django this is as easy as the following:

class FooInline(admin.StackedInline):
     model = Foo
     classes = ['collapse']
aris
  • 18,045
  • 1
  • 23
  • 26
3

My current solution, based on others listed here, has the following features:

  • Only collapses stacked inlines
  • Does not collapse inlines that contain an error
  • Does not collapse the 'empty' inline.

It's a Javascript solution, which means it needs to be injected into your page/template somehow.

It requires jQuery be loaded on the page by the time it is executed. Modern versions of Django have this.

$(function(){
  // Find all stacked inlines (they have an h3, with a span.inline_label).
  // Add a link to toggle collapsed state.
  $('.inline-group h3 .inline_label').append(' (<a class="collapse-toggle" href="#">Show</a>)');
  // Collapse all fieldsets that are in a stacked inline (not .tabular)
  $('.inline-group :not(.tabular) fieldset').addClass('collapsed');
  // Click handler: toggle the related fieldset, and the content of our link.
  $('.inline-group h3 .inline_label .collapse-toggle').on('click', function(evt) {
    $(this).closest('.inline-related').find('fieldset').toggleClass('collapsed');
    text = $(this).html();
    if (text=='Show') {
      $(this).html('Hide');
    } else {
      $(this).html('Show');
    };
    evt.preventDefault();
    evt.stopPropagation();
  });
  // Un-collapse empty forms, otherwise it's 2 clicks to create a new one.
  $('.empty-form .collapse-toggle').click();
  // Un-collapse any objects with errors.
  $('.inline-group .errors').closest('.inline-related').find('.collapse-toggle').click();
});
Matthew Schinckel
  • 32,344
  • 6
  • 71
  • 109
3

From django 1.10, We can now add extra css classes to InlineModelAdmin as well.

A list or tuple containing extra CSS classes to apply to the fieldset that is rendered for the inlines. Defaults to None. As with classes configured in fieldsets, inlines with a collapse class will be initially collapsed and their header will have a small “show” link.

Docs

Sagar R
  • 1,241
  • 9
  • 16
2

Here's how I solved it, but it feels too much like a hack (for a hack).

I used jQuery hosted from Google APIs to modify the DOM, taking advantage of Django's own 'show/hide' script. If you look at the html source of an admin page, the last script loaded is this:

<script type="text/javascript" src="/media/admin/js/admin/CollapsedFieldsets.js"></script>

The comments in that file gave me the idea: Leverage ModelAdmin media definitions to load my own dom-altering script.

from django.contrib import admin
from django.contrib.admin.sites import AdminSite
from myapp.models import *
import settings
media = settings.MEDIA_URL

class MyParticularModelAdmin(admin.ModelAdmin):
    # .....
    class Media:
          js = ('http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js',
              media+'js/addCollapseToAllStackedInlines.js')
# .....

And then inside of the referenced javascript file:

// addCollapseToAllStackedInlines.js
$(document).ready(function() {
  $("div.inline-group").wrapInner("<fieldset class=\"module aligned collapse\"></fieldset>");
});

The end results only works on StackedInline, NOT TabularInline.

Daniel Rhoden
  • 5,977
  • 6
  • 23
  • 28
  • This relies on the order javascript is executed (this before django's) and will not always work. – ionelmc Jul 08 '11 at 20:55
2

A couple of improvements on gerdemb's answer. Adds the 'Show' and 'Hide' text appropriately, and lets you specify the tabular inline names in a list beforehand:

$(document).ready(function(){
var tabNames = ['Inline Name 1', 'Inline Name 2', 'Inline Name 3'];
for (var x in tabNames)
{
    var selector = "h2:contains(" + tabNames[x] + ")";
    $(selector).parent().addClass("collapsed");
    $(selector).append(" (<a class=\"collapse-toggle\" id=\"customcollapser\""+ x + " href=\"#\"> Show </a>)");
};    
$(".collapse-toggle").click(function(e) {
    $(this).parent().parent().toggleClass("collapsed");
    var text = $(this).html();
    if (text==' Show ') {
        $(this).html(' Hide ');
        }
    else {
        $(this).html(' Show ');
    };
    e.preventDefault();
});
});
nosforz
  • 39
  • 4
0

If you want collapsible inline model then,

class AAAAdmin(admin.StackedInline):
    model = AAA
    classes = ['collapse', 'show']

If you want the grouping of fields collapsible then,

fieldsets = (
    ("Basic Details", {'fields': (
        "title", "street_line1", "street_line2", "city", "state", "country", "zipcode",
        "additional_code", "zone", "contact_no"
    )}),
    ("Google Map Related Details", {"classes": ['collapse', 'show'], 'fields': (
        "location", "longitude", "latitude", "google_map_link"
    )}),
)
Dharm Shah
  • 61
  • 2