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

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

    И тут на помощь приходит 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 за ценные замечания на этапе подготовки статьи.
    Метки:
    Поделиться публикацией
    Похожие публикации
    Комментарии 45
    • +4
      Очень полезная статья, как раз занимаюсь пилением админки… спасибо вам за описание…
      • +1
        Очень здорово и красиво. Есть ещё django-grappelli(http://code.google.com/p/django-grappelli/wiki/screenshots).

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

            Кстати, план ребят из grappelli — использовать django-admin-tools в качестве «дэшборда» ко всему остальному. См. bitbucket.org/fetzig/grappelli-admin-tools/overview
          • +2
            Отличная статья
            • 0
              Спасибо за статью. С интересом, жду продолжения.
              • +1
                Даже не знал что такое возможно, буду пробовать, спасибо!
                • НЛО прилетело и опубликовало эту надпись здесь
                  • 0
                    Давайте еще о Зенд фреймворке поговорим :)
                  • 0
                    Про графики было бы интересно почитать.
                    • 0
                      Мне кажется это обычные DIV-ы с кастомным style=«height»
                    • 0
                      Ошибку кажет:
                      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
                        посмотрите в settings на TEMPLATE_CONTEXT_PROCESSORS там должна быть строчка 'django.core.context_processors.request'

                        у меня из-за ее отсутствия ошибка была
                        • 0
                          Спасибо, помогло!
                          • НЛО прилетело и опубликовало эту надпись здесь
                            • 0
                              А можно подробности почему?
                        • +2
                          Как же досадно видеть такую лень (или несообразительность).
                          На сайте проекта есть скриншоты админки.
                          Вот один из них: www.izimobil.org/django-admin-tools/images/capture-2-small.png
                          Казалось бы, сверни свой браузер, установи нужную ширину, получи нормальную картинку, которая влезает на страницу без уменьшения. Но увы.
                          • 0
                            спасибо за замечание, Жан-Луи все поправил)
                          • +7
                            В кои-то веки авторская статья в стиле «того» хабра, а не репост новости, унылый перевод или очередное изобретение колеса. Спасибо.
                          • 0
                            михаил, как всегда, пишет отличные статьи, спасибо ему за это.

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

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

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

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

                                          Код этой дурацкой ссылки —
                                          <a class="changelink" ...>Изменить</a>
                                          • 0
                                            Спасибо! Думал есть более православный метод :)
                                            • 0
                                              Там в начале статьи написано что для админки не очень много православних методов)
                                              • 0
                                                А вообще я лох. Есть православный метод — создаешь в папке шаблонов папку 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
                                          Очень красиво. Честно говоря, даже не думал, что из этой довольно жесткой штуки можно сделать такую конфетку.
                                          • 0
                                            Скажите, чем вы рисовали такие симпатичные графики?
                                            • 0
                                              Тем кто будет впоследствии это читать habrahabr.ru/blogs/python/105627/ — про граффики и пр.
                                              • 0
                                                Хотел скачать переводы с transifex, че-т не получается (ссылка не активна). В чем может быть проблема?
                                                • 0
                                                  Не знаю, а зачем скачивать переводы с transifex?
                                                • 0
                                                  Оффтоп. Сейчас nadovmeste.ru (kupikupon) сделан на drupal, если не ошибаюсь. Почему решили перейти?
                                                  • 0
                                                    Там никто не переходил, а скорее наоборот: КупиКупон уже был большим и на друпале, когда купил НадоВместе, выкидывать свой движок и менять команду разработчиков они не стали, тут их вполне можно понять, технологии — это далеко не все.

                                                    Мы в итоге с их программистами посидели и аккаунты джанговских пользователей в друпал проэкспортировали, НадоВместе поработал потом еще пару месяцев в полузакрытом режиме (пока срок действия всех купонов не закончился — ну чтоб люди распечатать их могли), и тогда уже редирект сделали окончательно.
                                                  • 0
                                                    Ребята в чем может быть проблема, админка «кривит»: imm.io/QlVn
                                                    Грешил на то что не подгружаются некоторые .css/.js, но вроде все в норме, dev сервер не говорит об 404-ой ошибке
                                                    • 0
                                                      очередная чудовищная джанго свистоподелка
                                                      смотришь на такую и не видишь отличия от того как пхпник пытается встроить google/jquery плагин в уже работающую страницу на MooTools
                                                      то-есть для него, для тупого как молоток аникея, невдомёк, что это разные вещи, для него это просто какие то файлы и он считает, что если их побольше натолкать в свой код то всё будет прекрасно работать
                                                      так и этот модуль, впрочем как большинство джангосвистелок
                                                      посмотрите как он включается в проект, не через import не через from
                                                      а просто, через парсинг INSTALLED_APPS
                                                      а как управляется и расширяется, конечно же точно так же, через парсинг строк
                                                      вот точно такой же подход как этих тупых аникеев, которые копипастят со всяких форумов JS вставки в свой код
                                                      ни какого понимания и даже желания понимать как это работает, только бы побыстрее хоть чтото заработало
                                                      а проходит код, два, три и при очередном обновлении что-то как всегда ломается или Django или в её поделочных модулях и всё, парсинг строк ни как не локализует ошибку, а джанга после того как напарсилась текста досыта, попыталась загрузить, не получилось и она летит дальше, лишь бы у тупого аникея поскорее хоть что-то запустилось, лишь он чувствовал что он что-то может, лишь бы он не думал сам

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

                                                      Интересные публикации