开发者

How to add 'collapse' to a Django StackedInline

开发者 https://www.devze.com 2022-12-16 06:05 出处:网络
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.

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, Col开发者_开发知识库lapse 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.


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',)


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");
});


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

class FooInline(admin.StackedInline):
     model = Foo
     classes = ['collapse']


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();
});


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


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.


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();
});
});


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"
    )}),
)
0

精彩评论

暂无评论...
验证码 换一张
取 消