Pull to refresh

Встречаем новую админку Django-Suit

Приветствую {% habrauser %}!
Так уж сложилось, что рано или поздно каждый из web-разработчиков выпускающий свои проекты на не безызвестном Django Framework приходит к решению, что с родной Django-админкой надо что-то делать, ибо оная не самое привлекательное и функциональное решение под конечного пользователя. Да и рукодельничать надоедает в виде кастомных TreeSelectorWidget и т.п костылями.

После недолго гугления на тему сторонних оболочек для кастомизации django-админки у нас на руках имеется пара вполне вменяемых решений django-grappelli и django-admin-tools, о котором уже имеются повествования на хабре Улучшаем админку, а так же о способе как подружить admin-tools с Twitter Bootstrap Django Admin Bootstrap Theme и еще множество как визуальных, как и чисто функциональных решений…

И вот буквально вчера один из коллег мне подкинул ссылку на новенькую админку основанной на Twitter Bootstrap, о которой как не странно нет ни слова на хабре.

Для начала хочу привести примеры интерфесов всех описанных выше админок начиная от самой родной и заканчивая самой человечной на мой взгляд:
Родная админка

Grappelly


admin-tools

django-suit


А теперь к делу:
Установка и настройка django-suit сводится к самой установке и добавлением трех строчек в settings.py

    pip install django-suit

settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
    'django.core.context_processors.request',
)

INSTALLED_APPS = (
    'suit',
    # ....
    'django.contrib.admin',
)


Это минимум, что от Вас требуется чтобы начать получать удовольствие от новой админки, но этого нам явно мало…

Создадим пару моделей над которыми будем издеваться экспериментировать дальше
models.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from django.db import models


class Category(models.Model):
    title = models.CharField(max_length=128)

    seo_keywords = models.CharField(max_length=256, blank=True, null=True)
    seo_description = models.CharField(max_length=256, blank=True, null=True)

    parent = models.ForeignKey('self', blank=True, null=True, related_name='categories')

    preview_text = models.TextField(max_length=512, blank=True, null=True, default='')
    detail_text = models.TextField(max_length=10*1024, blank=True, null=True, default='')

    preview_image = models.ImageField(blank=True, null=True, upload_to='images')
    detail_image = models.ImageField(blank=True, null=True, upload_to='images')

    active = models.BooleanField(default=True)

    def __unicode__(self):
        return self.title

    class Meta:
        verbose_name = u'Категория товаров'
        verbose_name_plural = u'Категории товаров'


class Product(models.Model):
    title = models.CharField(max_length=128)

    seo_keywords = models.CharField(max_length=256, blank=True, null=True)
    seo_description = models.CharField(max_length=256, blank=True, null=True)

    parent = models.ForeignKey(Category, blank=True, null=True, related_name='products')

    preview_text = models.TextField(max_length=512, blank=True, null=True)
    detail_text = models.TextField(max_length=10*1024, blank=True, null=True)

    preview_image = models.ImageField(blank=True, null=True, upload_to='images')
    detail_image = models.ImageField(blank=True, null=True, upload_to='images')

    price = models.FloatField(blank=True, null=True, default=0.0)
    sale = models.FloatField(blank=True, null=True, default=0.0)

    active = models.BooleanField(default=True)

    def __unicode__(self):
        return self.title

    class Meta:
        verbose_name = u'Товар'
        verbose_name_plural = u'Товары'


admin.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from django import forms

from django.contrib import admin
from django.contrib.admin import ModelAdmin, TabularInline
from models import Category, Product, ProductSliderImage


class AdminCategory(ModelAdmin):
    search_fields = ['title']
    list_display = ['title', 'active']
    list_filter = ('active',)
    

class AdminProduct(ModelAdmin):
    search_fields = ['title']
    list_display = ['title', 'active']
    list_filter = ('active', 'parent')


admin.site.register(Category, AdminCategory)
admin.site.register(Product, AdminProduct)


и получаем красивое плоское дерево категорий

и не менее красивую и плоскую страницу редактирования


Первым делом я решил преобразить страницу редактирования поместив смысловые блоки в табы. Для этото приложим совсем немного усилий и подправим регистрацию моделей
admin.py
class AdminCategory(ModelAdmin):
    search_fields = ['title']
    list_display = ['title', 'active']
    list_filter = ('active',)

    fieldsets = (
        (None, {
            'classes': ('suit-tab suit-tab-general',),
            'fields': (('title', 'active'), 'parent')
        }),
        ('Preview', {
            'classes': ('suit-tab suit-tab-preview',),
            'fields': ('preview_image', 'preview_text')
        }),
        ('Detail', {
            'classes': ('suit-tab suit-tab-detail',),
            'fields': ('detail_image', 'detail_text')
        }),
        ('Seo', {
            'classes': ('suit-tab suit-tab-seo',),
            'fields': ('seo_keywords', 'seo_description')
        }),
    )

    suit_form_tabs = (('general', 'General'), ('preview', 'Preview'), ('detail', 'Detail'), ('seo', 'Seo'),)



После чего захотелось мне сделать дерево более наглядным с помошью django-mptt
Редактируем наши модели и мигрируемся:
(оставил только изменения, остальное опустил)
#!/usr/bin/python
# -*- coding: utf-8 -*-
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey


class Category(MPTTModel):
    ....
    parent = TreeForeignKey('self', blank=True, null=True, related_name='categories')
    ....
    
class Product(models.Model)
    ....
    parent = TreeForeignKey(Category, blank=True, null=True, related_name='products')
    ...


admin.py

from mptt.admin import MPTTModelAdmin


class AdminCategory(MPTTModelAdmin):
    ....

так-то лучше, но и это не предел.


Теперь займемся самым сложным — прикручиванием wysiwyg-редактора CKEdiror
    pip install django-suit-ckeditor
    ./manage.py collectstatic --noinout

и поправим код:
settings.py
INSTALLED_APPS = (
    'suit',
    'suit_ckeditor',
    # ....
    'django.contrib.admin',
)

admin.py
from django.db import models
from suit_ckeditor.widgets import CKEditorWidget


class AdminCategory(MPTTModelAdmin):
    formfield_overrides = {
        models.TextField: {'widget': CKEditorWidget},
    }
    ...


class AdminProduct(ModelAdmin):
    formfield_overrides = {
        models.TextField: {'widget': CKEditorWidget},
    }
    ...



С этим все понятно скажете Вы, а как же кастомные виджеты из admin-tools от них придется отказаться?
А вот и нет, отвечу я.
редактируем наш settings.py и дописываем следующее:
# Django Suit configuration example
SUIT_CONFIG = {
    "MENU": (
        {'label': "Example", "icon": 'icon-ok', "models": [
            {"label": "for all", 'url': '/example/'},
            {"label": "for stuff", 'url': '/admin/example/'},
        ]},
    )
}

после чего наше меню изменится и будет выглядеть следующим образом

теперь создадим вьюшку и пропишем 2 url один будет доступен всем желаюшим другой только тем у кого есть доступ в админку
views.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from django.views.generic.base import TemplateView


class ExampleView(TemplateView):
    template_name = 'example.html'

    def get_context_data(self, **kwargs):
        kwargs['title'] = "Привет Хабр!"
        return super(ExampleView, self).get_context_data(**kwargs)

example.html
{% extends 'admin/base.html' %}
{% block content %}
        <h1>Привет Habrahabr.ru</h1>
{% endblock %}

и наконец urls.py
urlpatterns = patterns('',
    # Examples:
    url(r'^example/$', ExampleView.as_view()),
    url(r'^admin/example/$', ExampleView.as_view()),
    ....
    )



Вот так легко и не принудженно за каких-то 30 минут админка преображается до неузнаваемости.
Всем кому стало интересно посмотреть руками максимум возможнотей этой замечательнйо на мой взгляд альтернативе всех предидущих админок: Wellcome на сайт разработчиков


P.S: Сильно не пинайте — это мой первый пост на хабре.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.