English 中文(简体)
Django Admin - add collapse to a fieldset, but have it start expanded
原标题:

Is there a way to make a fieldset collapsible, but start expanded? When you add collapse to the fieldset classes, it gets the functionality but starts collapsed. I ve taken a look at the JS that shows/hides the fieldset content, but it doesn t look like there s anything in there to do what I d like it to, so I m assuming I ll have to roll my own. Just wanted to check before I went through that effort.

最佳回答

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

问题回答

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

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 ,]
    })
]

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

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.

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

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/

So this one worked for me:

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

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




相关问题
How to get two random records with Django

How do I get two distinct random records using Django? I ve seen questions about how to get one but I need to get two random records and they must differ.

Moving (very old) Zope/Plone Site to Django

I am ask to move data from a (now offline) site driven by Plone to a new Django site. These are the version informations I have: Zope Version (unreleased version, python 2.1.3 ) Python Version 2.1....

Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

Flexible pagination in Django

I d like to implement pagination such that I can allow the user to choose the number of records per page such as 10, 25, 50 etc. How should I go about this? Is there an app I can add onto my project ...

is it convenient to urlencode all next parameters? - django

While writing code, it is pretty common to request a page with an appended "next" query string argument. For instance, in the following template code next points back to the page the user is on: &...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

热门标签