24.08

Произвольный порядок филдсетов в форме редактирования джанго-админки

Бывает с ростом приложения форма редактирования объектов сильно разростается. Чаще всего большинство полей в форме необязательные, либо могут заполняться автоматически на основе каких-то данных. Если скрыть эти поля, то необходимо писать интерфейс для их редактирования, потомучто бывает нужно их изменять (иначе зачем они были добавлены).

Данное противоречие можно легко разрешить поделив большую сложную форму на несколько простых с помощью табов. Однако не все так просто.

В django-админке можно группировать поля с помощью филдсетов, но инлайны с помощью филдсетов группировать мы не можем (по крайне мере пока). В стандартном шаблоне они генерируются после филдсетов.

Для того чтобы сделать отдельные филдсеты табами, можно использовать jquery-ui. Это достаточно просто и можно обойтись даже без переопределения стандартного шаблона и минимальным использованием JavaScript.

Если необходимо чтобы на одной вкладке было несколько филдсетов или филдсеты вместе с инлайнами, то либо пишем JS код, упорядочивающий нужным образом части формы, либо переопределяем шаблон.

Если выберем второй вариант, то сталкиваемся с проблемой - из шаблона не можем получить доступ к произвольному филдсету, поскольку они создаются только в итераторе.

Решаем данную проблему с помощью шаблонного тэга:

@register.inclusion_tag('admin/includes/fieldset.html', takes_context=True)
def render_fieldset(context, num):
    adminform = context['adminform']
    
    def get_fieldset(adminform, num):
        try:
            name, options = adminform.fieldsets[num]
        except KeyError:
            return None
        return Fieldset(adminform.form, name,
                readonly_fields=adminform.readonly_fields,
                model_admin=adminform.model_admin,
                **options
            )

    return {
        'fieldset' : get_fieldset(adminform, int(num)),
    }

В шаблоне вместо

{% for fieldset in adminform %}
  {% include "admin/includes/fieldset.html" %}
{% endfor %}

{% block after_field_sets %}{% endblock %}

{% for inline_admin_formset in inline_admin_formsets %}
    {% include inline_admin_formset.opts.template %}
{% endfor %}

{% block after_related_objects %}{% endblock %}

используем примерно следующее

         <div id="tabs">
                <ul>
                    <li id="tabbtn-1"><a href="#tab-1">Контент</a></li>
                    <li id="tabbtn-2"><a href="#tab-2">Категории</a></li>
                    <li id="tabbtn-3"><a href="#tab-3">Связи</a></li>
                    <li id="tabbtn-4"><a href="#tab-4">Параметры</a></li>
                    <li id="tabbtn-5"><a href="#tab-5">SEO</a></li>
                </ul>
                <div id="tab-1">
                    {% render_fieldset 0 %}
                </div>
                <div id="tab-2">
                    {% with inline_admin_formsets.0 as inline_admin_formset %}{% include inline_admin_formset.opts.template %}{% endwith %}
                    {% render_fieldset 1 %}
                </div>                        
                <div id="tab-3">
                    {% render_fieldset 2 %}
                    {% with inline_admin_formsets.1 as inline_admin_formset %}{% include inline_admin_formset.opts.template %}{% endwith %}
                </div>
                <div id="tab-4">
                    {% render_fieldset 3 %}
                </div>
                <div id="tab-5">
                    {% with inline_admin_formsets.2 as inline_admin_formset %}{% include inline_admin_formset.opts.template %}{% endwith %}
                </div>
            </div>
{% block after_field_sets %}{% endblock %}
{% block after_related_objects %}{% endblock %}

Чтобы из этого получились табы в блок javascript добавим необходимые скрипты

{% block javascripts %}{{ block.super }}
    <link type="text/css" href="{{ MEDIA_URL }}lib/jquery/ui/css/smoothness/jquery-ui-1.8.1.custom.css" rel="stylesheet" />
    <script type="text/javascript" src="{{ MEDIA_URL }}lib/jquery/jquery-1.4.2.min.js"></script>
    <script type="text/javascript" src="{{ MEDIA_URL }}lib/jquery/ui/jquery-ui-1.8.1.custom.min.js"></script>
    <script type="text/javascript">
$(document).ready(function() {
    $("#tabs").tabs();
  });
</script>
{% endblock %}

Версии jquery и jquery-ui конечно же могут отличаться, код выдран из готового приложения.

inline_admin_formset.opts.template

© 2010 Алексей Камедов

При копировании материалов блога ссылка на источник обязательна.