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 c开发者_如何学JAVAontent, 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.
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',]
})
]
django-grappelli provides this as one of the features. Here's the wiki page about that feature (with screenshots).
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);
});
});
}
精彩评论