[Fixed]-Django Admin – add collapse to a fieldset, but have it start expanded

4👍

django-grappelli provides this as one of the features. Here’s the wiki page about that feature (with screenshots).

15👍

admin.py:

class PageAdmin(admin.ModelAdmin):
    fieldsets = (
        (None, {
            'fields': ('title', 'content', )
        }),
        ('Other Informations', {
            'classes': ('collapse', 'open'),
            'fields': ('slug', 'create-date',)
        }),
    )

templates/app_label/model_name/change_form.html:

{% extends "admin/model_name/change_form.html" %}

{% block extrahead %}
    {{ block.super }}
    <script src="{{ STATIC_URL }}admin/js/collapse-open.js" type="text/javascript"></script>
{% endblock %}

static/admin/js/collapse-open.js:

(function($) {
    $(document).ready(function() {
        $('fieldset.collapse.open').removeClass('collapsed');
    });
})(django.jQuery);

13👍

I know this is real old but I also just came across this issue. After thinking about it way too hard I found an easy solution which seems to get the job done involving 0 plugins or additional js.

Within fieldsets construct Add ‘collapse in’ rather than ‘collapse’ to class:

fieldsets = [
    ('Start Expanded', {
    'fields': ['field1', 'field2', 'field3'], 
    'classes': ['collapse in',]
    })
]

3👍

Accoding with the grappelli docs only need to add “classes” : (‘grp-collapse grp-closed’)

for example

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

note: if you use grappelli version < 2.4 use ‘grp-closed’ instead ‘collapse-closed’*
actually ‘collapse-close’ still is working but is recommended to use the new classes

👤elin3t

2👍

Starting from Setomidor answer, I’d like to suggest a simpler alternative that does exactly what you want (if Grappelli is not an option, obviously).

Create the template override as explained (admin/(app)/(model)/change_form.html) and instead of removing the collapsible effect for the “add” model case, simply call the click method of the field-set collapser (i.e. the small link with the show/hide text) to have the whole field-set expanded as soon as the page loads.

1👍

The quickest hack I could find was to add a new class start-open to the fieldset

classes = ['collapse', 'start-open']

and then modify static/admin/js/collapse.js.

from:

    // Add toggle to anchor tag
    var toggles = document.querySelectorAll('fieldset.collapse a.collapse-toggle');
    var toggleFunc = function(ev) {
        ev.preventDefault();
        var fieldset = closestElem(this, 'fieldset');
        if (fieldset.classList.contains('collapsed')) {
            // Show
            this.textContent = gettext('Hide');
            fieldset.classList.remove('collapsed');
        } else {
            // Hide
            this.textContent = gettext('Show');
            fieldset.classList.add('collapsed');
        }
    };
    for (i = 0; i < toggles.length; i++) {
        toggles[i].addEventListener('click', toggleFunc);
    }

to:

    // Add toggle to anchor tag
    var toggles = document.querySelectorAll('fieldset.collapse a.collapse-toggle');
    // NEW: select toggles to open
    var open_toggles = document.querySelectorAll('fieldset.collapse.start-open a.collapse-toggle');
    var toggleFunc = function(ev) {
        ev.preventDefault();
        var fieldset = closestElem(this, 'fieldset');
        if (fieldset.classList.contains('collapsed')) {
            // Show
            this.textContent = gettext('Hide');
            fieldset.classList.remove('collapsed');
        } else {
            // Hide
            this.textContent = gettext('Show');
            fieldset.classList.add('collapsed');
        }
    };
    for (i = 0; i < toggles.length; i++) {
        toggles[i].addEventListener('click', toggleFunc);
    }
    // NEW: open toggles
    for (i = 0; i < open_toggles.length; i++) {
        toggles[i].click();
    }

0👍

Old question, but I ran into the same one and came up with an answer which can be implemented using standard django:

create file: admin/(app)/(model)/change_form.html in your templates directory to make your (model) of your (app) use that form file.

Add this code to the file:

{% extends "admin/change_form.html" %}

{% block extrahead %}
    <!-- Load superblock (where django.jquery resides) -->
    {{ block.super }}
    <!-- only do this on 'add' actions (and not 'change' actions) -->
    {% if add and adminform %}
    <script type="text/javascript">
        (function($) {
            $(document).ready(function($) {
                //Remove the 'collapsed' class to make the fieldset open
                $('.collapse').removeClass('collapsed');

                //Remove the show/hide links
                $('.collapse h2 a').remove();

                //Tidy up by removing the parenthesis from all headings
                var $headings = $(".collapse h2");
                $headings.each(function(i, current){
                    var str = $(current).text();
                    parenthesisStart = str.indexOf('(');
                    $(current).text(str.substring(0, parenthesisStart));
                });
            });                                 
        })(django.jQuery);                      
    </script>
    {% endif %}
{% endblock %}

For more information about using django.jQuery instead of “regular” jQuery, see: http://blog.picante.co.nz/post/Customizing-Django-Admin-with-jQuery–Getting–is-not-a-function/

0👍

So this one worked for me:

class PageAdmin(admin.ModelAdmin):
    fieldsets = (
        (None, {
            'fields': ('title', 'content', )
        }),
        ('Other Informations', {
            'classes': ('wide'),
            'fields': ('slug', 'create-date',)
        }),
    )
👤flix

0👍

With django 4.x, here is my admin/js/collapse.js
add start-open in class

'use strict';
{
    window.addEventListener('load', function() {
        // Add anchor tag for Show/Hide link
        const fieldsets = document.querySelectorAll('fieldset.collapse');
        // NEW: select toggles to open
        var open_toggles = document.querySelectorAll('fieldset.collapse.start-open');        
        for (const [i, elem] of fieldsets.entries()) {
            // Don't hide if fields in this fieldset have errors
            if (elem.querySelectorAll('div.errors, ul.errorlist').length === 0) {
                if (elem.classList[3] != 'start-open') {
                    elem.classList.add('collapsed');
                }
                const h2 = elem.querySelector('h2');
                const link = document.createElement('a');
                link.id = 'fieldsetcollapser' + i;
                link.className = 'collapse-toggle';
                link.href = '#';
                if (elem.classList[3] != 'start-open') {
                    link.textContent = gettext('Show');
                } else {
                    link.textContent = gettext('Hide');
                }
                h2.appendChild(document.createTextNode(' ('));
                h2.appendChild(link);
                h2.appendChild(document.createTextNode(')'));
            }
        }
        // Add toggle to hide/show anchor tag
        const toggleFunc = function(ev) {
            if (ev.target.matches('.collapse-toggle')) {
                ev.preventDefault();
                ev.stopPropagation();
                const fieldset = ev.target.closest('fieldset');
                if (fieldset.classList.contains('collapsed')) {
                    // Show
                    ev.target.textContent = gettext('Hide');
                    fieldset.classList.remove('collapsed');
                } else {
                    // Hide
                    ev.target.textContent = gettext('Show');
                    fieldset.classList.add('collapsed');
                }
            }
        };
        document.querySelectorAll('fieldset.module').forEach(function(el) {
            el.addEventListener('click', toggleFunc);
        });
    });
}   
👤AndyC

Leave a comment