Улучшаем админку

Одно из слабых мест джанго-админки — главная страница. Идея авто-группировки моделей по приложениям и вывод столбиком в одну колонку работает только на начальных этапах, дальше это становится просто неудобно — куча лишней информации и довольно сложные пути для того, чтобы добавить полезную. Ну, например, чтобы названия приложений писались русскими буквами — полностью перекрывать шаблон.

И тут на помощь приходит django-admin-tools. С этим приложением минут за 20 можно получить «приборную панель» с произвольной группировкой приложений/моделей, вкладками, любым числом колонок, различными блоками, которые каждый пользователь сможет расставить, как ему удобнее, скрывать и сворачивать по желанию, закладками, настраиваемым меню и удобным способом добавления во все это хозяйство всего, чего только можно придумать.

Вот так, например, сейчас выглядит админка к сайту НадоВместе:

image
(это только часть, вот скриншот целиком)

Разберемся поподробнее.

Установка


1. pip install -e hg+http://bitbucket.org/izi/django-admin-tools/#egg=django-admin-tools
Ставим дев-версию, т.к. я фанат дев-версий там много новых вкусных штук: например, упрощен API и добавлены группы. Если не установлен mercurial, то можно скачать последнюю ревизию архивом, распаковать и запустить python setup.py install.

2. Добавляем admin_tools в INSTALLED_APPS (обязательно до django.contrib.admin):

INSTALLED_APPS = (
    'admin_tools',
    'admin_tools.theming',
    'admin_tools.menu',
    'admin_tools.dashboard',    
    # ...
    'django.contrib.auth',
    'django.contrib.sites',
    'django.contrib.admin'
    # ... и другие приложения ...
)

3. python manage.py syncdb

4. подключаем в urls.py:

urlpatterns = patterns('',
    url(r'^admin_tools/', include('admin_tools.urls')),
    #... и т.д. ...
)

5. копируем медиа-файлы (js, css и картинки) в MEDIA_ROOT проекта. Что-то вроде этого — вы ведь используете virtualenv?

cp -r /home/kmike/envs/nadovmeste/src/django-admin-tools/admin_tools/media/admin_tools /path/to/yourproject/media/

Можно вместо копирования сделать симлинк или использовать django-static-files.

Все, можно зайти в админку и удивиться страшной пятнистой шапке тому, как все поменялось. Установка, как видите, вполне обычная, никаких джанговских файлов заменять не нужно (как в grappelli было когда-то).

Блоки


Самая полезная штука в django-admin-tools — это, конечно, блоки. Вы можете настроить, какие блоки и как показывать на заглавной странице, писать свои блоки и брать готовые.

1. Создаем заготовку для «приборной панели»:

python manage.py customdashboard

После этого в корне проекта появится файл dashboard.py с заготовкой. Можно его, в принципе, и руками написать.

В файле будет содержаться 2 класса: CustomIndexDashboard и CustomAppIndexDashboard — для главной страницы админки и страницы отдельного приложения. Нас тут будет интересовать класс CustomIndexDashboard.

2. Указываем в settings.py, что будем использовать свою «приборную панель» на заглавной странице админки:

ADMIN_TOOLS_INDEX_DASHBOARD = 'yourproject.dashboard.CustomIndexDashboard'

3. Для примера: объединим в одном блоке стандартные джанговские модели из auth и свои данные о профайлах, назвав при этом блок по-русски:

from admin_tools.dashboard import modules, Dashboard

class CustomIndexDashboard(Dashboard):

    def __init__(self, **kwargs):
        Dashboard.__init__(self, **kwargs)
        self.children.append(
            modules.ModelList(
                title = u'Пользователи',
                models=(
                    'django.contrib.auth.*',
                    'my_accounts.models.Profile',
                ),
            )
        )


В списке моделей указываются полные пути к моделям, которые требуется подключить. Все модели, которые перечислены в models, должны быть зарегистрированы в джанговской админке как обычно. Если моделей несколько, то можно их все не перечислять, т.к. есть поддержка *. Если вы включили кучу моделей через * и нужно из них убрать несколько, то есть симметричный параметру models параметр exclude со списком моделей, которые показывать не нужно (там тоже есть поддержка *).

Стандартные блоки


django-admin-tools включает в стандартную поставку несколько готовых блоков для приборной панели. Детальную информацию о них можно найти в документации. Тут будет просто краткий обзор + описание замечательного modules.Group, которого не было в документации на момент написания статьи.

Импортировать их следует так: from admin_tools.dashboard import modules

1. modules.ModelList — как мне кажется, это самый основной и полезный блок. Позволяет группировать произвольные модели в рамках одного блока.

image

2. modules.Group — еще один супер-полезный блок. Позволяет группировать любые другие блоки внутри себя. Блоки могут или располагаться друг над другом, или в виде «аккордеона», или во вкладках. Очень удобно, например, для графиков, или для отделения основных и часто используемых разделов от побочных.

image

Пример использования:

        self.children.append(modules.Group(
            title=u"Статистика",
            display="tabs",
            children=[
                nadovmeste_modules.Overview(),
                nadovmeste_modules.Subscribers(),
                nadovmeste_modules.Finances(),
                nadovmeste_modules.Users(),
            ]
        ))


В списке children можно указывать любые другие блоки, в.т.ч. разных типов. В примере тут не стандартные модули из admin_tools.dashboard.modules, а свои (о том, как их делать — позже).

Поддержки вложенных групп пока нет (а если точнее, то сейчас js при этом работает неправильно).

3. modules.LinkList — список произвольных ссылок. Внешние ссылки могут помечаться специальной иконкой, ссылки могут располагаться как горизонтально, так и в столбик.

image

4. modules.AppList — по сути, аналог главной страницы стандартной джанговской админки. Список приложений и моделей в них. Скажу по секрету, тут есть еще не документированный параметр models, который абсолютно аналогичен этому параметру в modules.ModelList — с той разницей, что потом модели будут сгруппированы по приложениям. Этот блок полезен, если хочется добавить все по-быстрому, или повторить обычную джанговскую админку — в остальных случаях, как мне кажется, лучше подходит ModelList. Хотя может это дело вкуса.

5. modules.RecentActions — список последних действий, как в стандартной джанговской админке. Не знаю, зачем он нужен :)

6. modules.Feed — позволяет показывать ленты RSS в админке.

Пишем свои блоки


Напишем, например, абсолютно бесполезный блок, который будет просто выводить какое-то сообщение, переданное ему в конструкторе.

1. Наследуемся от admin_tools.dashboard.modules.DashboardModule:

class MyModule(modules.DashboardModule):
    def is_empty(self):
        return self.message == ''

    def __init__(self, **kwargs):
        super(MyModule, self).__init__(**kwargs)
        self.template = 'my_blocks/hello.html'
        self.message = kwargs.get('message', '')


2. Делаем шаблон templates/my_blocks/hello.html

{% extends "admin_tools/dashboard/module.html" %}
{% block module_content %}
    <h4>{{ module.message  }}</h4>
{% endblock %}


Как видите, объект модуля передается в шаблон. Это означает, что можно передавать любые данные через его атрибуты (что мы и сделали в примере с message).

3. Подключаем блок в dashboard.py

self.children.append(MyModule(title=u"Приветствие", message = u'Привет!'))


Все, готово. Думаю, теперь понятно, как делать любые более сложные штуки, рисовать в блоках графики и тд. Готовим данные, делаем шаблон. Если в контексте шаблона нужен request, то переопределяйте метод init_with_context (по ссылке — пример).

Полученный блок можно будет таскать мышкой, сворачивать-разворачивать, располагать отдельно или во вкладке у modules.Group и тд. — наравне со стандартными блоками.

Да, еще, если нужно что-то просто дописать сверху или снизу стандартного блока, то можно свой блок/шаблон не делать, а воспользоваться атрибутами модуля pre_content и post_content.

Внешний вид


Люди достаточно осторожно подошли к дизайнерству, и новые элементы смотрятся вполне органично рядом со стандартными джанговскими. Но если вам тоже не нравится ненужный заголовок и кошмарная пятнистая стандартная шапка из django-admin-tools, то их проще всего убрать с помощью css. Хорошо бы еще логотип в шапку добавить. Заодно и с тем, как делать темы, разберемся.
image

1. Делаем css-файл со своей темой. Для примера можно посмотреть тему, которая используется в нашей админке, еще пример есть в стандартной поставке.

2. Подключаем файл с темой: в settings.py добавляем настройку
ADMIN_TOOLS_THEMING_CSS = 'css/theming.css' # путь относительно MEDIA_ROOT


Что дальше


В статье нет ничего про меню, закладки, настройку собственно приборных панелей, про панели для отдельных приложений. Обо всем этом можно почитать в документации. Если хотите помочь проекту, подключившись к разработке — welcome. Если что не работает в django-admin-tools, то это я все сломал, если что-то сделано круто — напишите весточку David Jean Louis.

Небольшие хитрости


Если вы обновили модули в своей приборной панели (добавили, удалили, поменяли местами), и после этого все куда-то уехало, то удалите записи из DashboardPreferences.

Статистика на скриншоте — с тестового сервера, реальные данные nadovmeste.ru не «спалил». Если интересно, то в следующей статье расскажу, как заполнять базу большим количеством тестовых данных, и как строк за 5 кода (включая шаблон) получать любые графики со статистикой (как, например, на скриншоте — график со статистикой регистраций пользователей по дням).

Да, спасибо obiwanus и leoglu за ценные замечания на этапе подготовки статьи.
+95
8 июля 2010, 08:51
292
kmike 129,7 G+

комментарии (43)

+4
devosx #
Очень полезная статья, как раз занимаюсь пилением админки… спасибо вам за описание…
+1
Narada #
Очень здорово и красиво. Есть ещё django-grappelli(http://code.google.com/p/django-grappelli/wiki/screenshots).

Тут главный вопрос — в совместимости с django reusable app, которые рассчитаны на стандартный интерфейс, например django-cms, приходилось допиливать для нормальной интеграции с grappelli.
0
obiwanus #
Про граппелли в статье упоминается. По крайней мере раньше (не знаю, как сейчас) его прикручивание было гораздо менее удобно.
+1
Narada #
тот же самый процесс: pip install django-grappelli, правим settings.py,urls.py, syncdb и поехали.
+1
kmike #
Я видимо застал еще то время, когда нужно было обычные медиа-файлы от админки полностью заменить на те, что в grappelli, поэтому так написал.
+1
kmike #
у django-admin-tools с совместимостью должно быть гораздо лучше, чем у grappelli, т.к. переделка шаблонов и стилей менее кардинальная. Grappelli практически все шаблоны и стили заменили на свои, в django-admin-tools стандартные стили с небольшими доделками.

Кстати, план ребят из grappelli — использовать django-admin-tools в качестве «дэшборда» ко всему остальному. См. bitbucket.org/fetzig/grappelli-admin-tools/overview
+2
Rastler #
Отличная статья
0
ZoomLS #
Спасибо за статью. С интересом, жду продолжения.
+1
Biggo #
Даже не знал что такое возможно, буду пробовать, спасибо!
НЛО прилетело и опубликовало эту надпись здесь
0
obiwanus #
Давайте еще о Зенд фреймворке поговорим :)
0
Voldar #
Про графики было бы интересно почитать.
0
seriyPS #
Мне кажется это обычные DIV-ы с кастомным style=«height»
0
andreysmind #
Ошибку кажет:
In template /Library/Python/2.6/site-packages/django_admin_tools-0.2.0-py2.6.egg/admin_tools/menu/templates/admin/base_site.html, error at line 17
13
14 {% block nav-global %}
15 {% if user and user.is_authenticated %}
16 {% if not is_popup %}
17 {% admin_tools_render_menu %}
18 {% endif %}
19 {% endif %}

админ-тулз устанавливал просто через easy_install
За статью большое спасибо, этих возможностей нехватало для такой хваленой Джанго-админки.
+1
plazix #
посмотрите в settings на TEMPLATE_CONTEXT_PROCESSORS там должна быть строчка 'django.core.context_processors.request'

у меня из-за ее отсутствия ошибка была
0
andreysmind #
Спасибо, помогло!
0
rudyryk #
Блин, они подталкивают ко злу. 'django.core.context_processors.request' в TEMPLATE_CONTEXT_PROCESSORS — это же концептуальный overhead.
0
Biggo #
А можно подробности почему?
+2
homm #
Как же досадно видеть такую лень (или несообразительность).
На сайте проекта есть скриншоты админки.
Вот один из них: www.izimobil.org/django-admin-tools/images/capture-2-small.png
Казалось бы, сверни свой браузер, установи нужную ширину, получи нормальную картинку, которая влезает на страницу без уменьшения. Но увы.
0
kmike #
спасибо за замечание, Жан-Луи все поправил)
+7
TimTowdy #
В кои-то веки авторская статья в стиле «того» хабра, а не репост новости, унылый перевод или очередное изобретение колеса. Спасибо.
+4
obiwanus #
kmike еще торт
0
tibalt #
михаил, как всегда, пишет отличные статьи, спасибо ему за это.

как раз недавно мучал стандартную админку, вывернул ей все кишки, было очень неудобно) теперь кастомизация будет проходить гораздо приятнее.
0
azl #
Спасибо, попробую )
0
obiwanus #
Уж извольте, попробуйте)
0
tibalt #
кстати, в одной буржуйской презентации по кастомизации админки, наряду с грапелли видел ссылки на проекты github.com/ella/ella и gondolacms.com/
кто-нить с такими игрался?
0
helm2004 #
Пишет «Caught an exception while rendering: Reverse for 'admin-tools-dashboard-set-preferences' with arguments '()' and keyword arguments '{}' not found.» В чём может быть причина?
0
kmike #
Закомментировал у себя строку
url(r'^admin_tools/', include('admin_tools.urls')),
из urls.py, выпала ровно эта же ошибка. Вы не подключили значит url'ы.
0
helm2004 #
Извените, как говориться, нужно внимательней читать. Спасибо большое!
0
korkholeh #
Большое спасибо за статью, как раз искал нечто подобное. Теперь все работает прекрасно.
0
sapegin #
Очень интересно, спасибо!

А не знаете, можно ли с помощью этой штуки удалить дурацкие ссылки «Изменить» рядом с каждой моделью?
+1
obiwanus #
Код этой дурацкой ссылки — Изменить

Пропишите для главной страницы свой класс и можете указать в css
.yourclass .changelink { display: none }

Это можно сделать и без «этой штуки».
+1
obiwanus #
Чорт, код убрался. Читайте:

Код этой дурацкой ссылки —
<a class="changelink" ...>Изменить</a>
0
sapegin #
Спасибо! Думал есть более православный метод :)
0
obiwanus #
Там в начале статьи написано что для админки не очень много православних методов)
0
obiwanus #
А вообще я лох. Есть православный метод — создаешь в папке шаблонов папку admin и копируешь туда файл index.html из django.contrib.admin.templates.

В файле index.html есть такой код:
            {% if model.perms.change %}
                <td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
            {% else %}
                <td> </td>
            {% endif %}

Просто его удаляешь и все.
0
neithere #
Очень красиво. Честно говоря, даже не думал, что из этой довольно жесткой штуки можно сделать такую конфетку.
0
glader #
Скажите, чем вы рисовали такие симпатичные графики?
0
kurd #
Тем кто будет впоследствии это читать habrahabr.ru/blogs/python/105627/ — про граффики и пр.
0
megido #
Хотел скачать переводы с transifex, че-т не получается (ссылка не активна). В чем может быть проблема?
0
kmike #
Не знаю, а зачем скачивать переводы с transifex?
0
oleg_fadeev #
Оффтоп. Сейчас nadovmeste.ru (kupikupon) сделан на drupal, если не ошибаюсь. Почему решили перейти?
0
kmike #
Там никто не переходил, а скорее наоборот: КупиКупон уже был большим и на друпале, когда купил НадоВместе, выкидывать свой движок и менять команду разработчиков они не стали, тут их вполне можно понять, технологии — это далеко не все.

Мы в итоге с их программистами посидели и аккаунты джанговских пользователей в друпал проэкспортировали, НадоВместе поработал потом еще пару месяцев в полузакрытом режиме (пока срок действия всех купонов не закончился — ну чтоб люди распечатать их могли), и тогда уже редирект сделали окончательно.

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