Custom Django admin interface.
Project description
paper-admin
Custom Django admin interface based on Bootstrap 4.
Requirements
- Python >= 3.6
- Django >= 2.2
Installation
Add paper_admin
to your INSTALLED_APPS setting before django.contrib.admin
.
INSTALLED_APPS = [
"paper_admin",
"paper_admin.patches.dal", # optional
"paper_admin.patches.django_solo", # optional
"paper_admin.patches.mptt", # optional
"paper_admin.patches.logentry_admin", # optional
"paper_admin.patches.tree_queries", # optional
# ...
"django.contrib.admin",
# ...
]
Patches
Некоторые сторонние библиотеки переопределяют стандартные
шаблоны Django и в рамках интерфейса paper_admin
выглядят инородно. По этой причине (а также для внедрения
дополнительного функционала) применяются патчи.
В состав paper_admin
включены следующие патчи:
-
paper_admin.patches.dal
Исправляет стили виджетов django-autocomplete-light -
paper_admin.patches.django_solo
Исправляет хлебные крошки в django-solo. -
paper_admin.patches.mptt
Адаптация django-mptt. Добавляет возможность сортировки узлов дерева (при указании свойстваsortable
). -
paper_admin.patches.logentry_admin
Исправление фильтров и скрытие ненужных кнопок в django-logentry-admin. -
paper_admin.patches.tree_queries
Добавление возможности сортировки узлов дерева для django-tree-queries.Необходимо использовать специальный класс
TreeNodeModelAdmin
вместоModelAdmin
:# admin.py from django.contrib import admin from paper_admin.patches.tree_queries.admin import TreeNodeModelAdmin # <-- from .models import MyTreeNode @admin.register(MyTreeNode) class MyTreeNodeAdmin(TreeNodeModelAdmin): ... sortable = "position"
Note: как правило, патчи должны быть указаны в INSTALLED_APPS
до библиотек,
которые они исправляют.
Сортировка объектов при помощи Drag & Drop
Для того, чтобы экземпляры модели можно было сортировать в интерфейсе администратора, необходимо выполнить два условия.
-
Добавить в модель числовое поле, которое будет хранить порядковый номер.
# models.py from django.db import models class MyModel(models.Model): position = models.IntegerField( "position", default=0 )
-
Указать название этого поля в свойстве
sortable
соответствующего подклассаModelAdmin
:# admin.py from django.contrib import admin class MyModelAdmin(admin.ModelAdmin): sortable = "position" # ...
Результат:
https://user-images.githubusercontent.com/6928240/125331456-0f1bb280-e359-11eb-8b17-b04be4b1e62c.mp4
Сохранение сортировки происходит через AJAX-запрос.
Таким же путём можно включить сортировку инлайн-форм, но в этом случае сортировка происходит с помощью кнопок и сохраняется вместе со всей страницей при нажатии кнопки "Save":
from django.contrib import admin
class TablularInline(admin.TabularInline):
sortable = "position"
# ...
Результат:
https://user-images.githubusercontent.com/6928240/125331956-b6004e80-e359-11eb-8422-832dfe37bb6c.mp4
Сортировка paper-admin
совместима с django-mptt
(если в INSTALLED_APPS
добавлен патч paper_admin.patches.mptt
).
Менять местами можно только те элементы, которые имеют общего родителя и находятся на одном уровне
вложенности:
https://user-images.githubusercontent.com/6928240/125340277-55760f00-e363-11eb-94d4-49a978cb7ae4.mp4
Вкладки
Форму добавления/редактирования объекта можно разделить на вкладки.
Список вкладок указывается в атрибуте tabs
:
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
class TablularInlines(admin.TabularInline):
# имя вкладки, на которой должен быть отображен формсет
tab = 'inlines-tab'
@admin.register(Page)
class PageAdmin(admin.ModelAdmin):
fieldsets = (
(_('First Section'), {
'tab': 'common-tab',
'fields': (
# ...
),
}),
(_('Second Section'), {
'tab': 'common-tab',
'fields': (
# ...
)
}),
(_('Links'), {
'tab': 'links-tab',
'fields': (
# ...
)
}),
)
tabs = [
('common-tab', _('General')),
('links-tab', _('Links')),
('inlines-tab', _('Inlines')),
]
inlines = (TablularInlines, )
Результат:
https://user-images.githubusercontent.com/6928240/125336032-4e003700-e35e-11eb-8399-9cff90ea7aca.mp4
Вкладки можно добавлять динамически, с помощью метода get_tabs
:
from django.contrib import admin
from .models import Page
@admin.register(Page)
class PageAdmin(admin.ModelAdmin):
def get_tabs(self, request, obj=None):
return [
# ...
]
Стилизация
Стилизация fieldset
Django даёт возможность
указать произвольные CSS-классы и описание для любого fieldset.
paper-admin
предоставляет набор готовых CSS-классов для стилизации fieldset:
paper-card--primary
paper-card--secondary
paper-card--info
paper-card--danger
paper-card--success
paper-card--warning
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
@admin.register(Page)
class PageAdmin(admin.ModelAdmin):
fieldsets = (
(_("Info Section"), {
"classes": ("paper-card--info", ),
"description": _("Description for the fieldset"),
"fields": (
# ...
),
}),
(_("Success Section"), {
"classes": ("paper-card--success",),
"fields": (
# ...
)
}),
(_("Danger Section"), {
"classes": ("paper-card--danger",),
"fields": (
# ...
)
}),
)
Результат:
Стилизация рядов таблицы
Для каждого ряда таблицы вызывается метод get_row_classes
, который должен вернуть
список CSS-классов, которые будут добавлены к тэгу <tr>
.
from django.contrib import admin
from .models import Page
@admin.register(Page)
class PageAdmin(admin.ModelAdmin):
def get_row_classes(self, request, obj):
if obj.name.startswith("M"):
return ["table-success"]
elif obj.name.startswith("P"):
return ["table-info"]
return []
Результат:
Стилизация inline-форм
Inline-формам тоже можно назначить произвольные CSS-классы с помощью метода
get_form_classes
:
from django.contrib import admin
class StackedInline(admin.StackedInline):
def get_form_classes(self, request, obj):
if obj.name.startswith("P"):
return ["paper-card--success"]
elif obj.name.startswith("M"):
return ["paper-card--info"]
return []
class TablularInlines(admin.TabularInline):
def get_form_classes(self, request, obj):
if obj.name.startswith("P"):
return ["table-success"]
elif obj.name.startswith("M"):
return ["table-info"]
return []
Результат:
Меню
Меню в сайдбаре настраивается путем заполнения списка PAPER_MENU
в settings.py
.
PAPER_MENU = [
dict( # Пункт меню для главной страницы
label=_("Dashboard"),
url="admin:index",
icon="fa fa-fw fa-lg fa-area-chart",
),
dict( # Пункт меню для приложения app
app="app",
icon="fa fa-fw fa-lg fa-home",
models=[
"Tag",
"Category",
"SubCategory",
]
),
"-", # Разделитель
"auth", # Приложение auth
"sites", # Приложение sites
]
Пункт меню может быть задан одним из четырех способов:
- Имя приложения (app_label).
Все модели выбранного приложения образуют подменю. Порядок моделей Django определяет автоматически. - Путь к модели (app_label.model_name).
Создаст пункт меню с заголовком, соответствующим названию модели и соответствующим URL. - Строка-разделитель ("-")
Добавляет горизонтальную линию. С помощью разделителей можно визуально группировать пункты меню. - Словарь.
Самый гибкий способ создания пункта меню. В словаре можно явным образом указать название пункта меню, его URL, иконку, CSS-классы и пункты подменю.
При использовании словаря можно указать следующие ключи:
label
:str
- заголовок пункта менюurl
:str
- URL или имя URL-шаблона (напримерapp:index
)icon
:str
- CSS-классы иконкиclasses
:str
- CSS-классы пункта менюperms
:str/list/callable
- права, необходимые для отображения пункта. Для определения суперюзера и сотрудников, можно использовать специальные значенияsuperuser
иstaff
соответственно.app
:str
- имя приложения. Неявно добавляется к именам моделей, указанным в пунктеmodels
.models
:list/dict
- дочерние пункты меню. Содержит список имен моделей приложения или пунктов подменю, которые можно задать в виде словаря.
Пример 1.
from django.urls import reverse_lazy
PAPER_MENU = [
dict(
app="app",
icon="fa fa-fw fa-lg fa-home",
models=[
dict(
label=_("Index"),
url=reverse_lazy("admin:app_list", kwargs={
"app_label": "app"
})
), # Произвольный пункт меню
"Tag", # Модель app.Tag
"Category", # Модель app.Category
]
),
"-", # Разделитель
"auth", # Приложение auth
]
Пример 2. Проверка прав.
С помощью параметра perms
можно укзать названия прав (Django permissions),
которые должен иметь пользователь, чтобы увидеть этот пункт меню.
На доступность страниц параметр perms
никак не влияет. Если пользователь знает
адрес страницы или ссылка на неё имеется где-то ещё, то пользователь сможет на неё
зайти.
PAPER_MENU = [
# Пункт меню приложения app увидят только сотрудники (staff),
# имеющие право на изменение модели `app.Tag`.
dict(
app="app",
perms=["staff", "app.change_tag"],
models=[
"Tag",
]
)
]
Бейдж (badge)
Полоса с текстом в сайдбаре.
Её основное предназначение - визуально обозначить окружение, в котором работает административный интерфейс. Так вы не перепутаете сервер разработки с продашеном.
Цвет полосы и текст устанавливаются в settings.py
:
PAPER_ENVIRONMENT_NAME = "development"
PAPER_ENVIRONMENT_COLOR = "#FFFF00"
Settings
PAPER_FAVICON
Путь к favicon-файлу, который будет использоваться в интерфейсе админиcтратора.
Default: "paper_admin/dist/assets/default_favicon.png"
PAPER_ENVIRONMENT_NAME
Текст на бейжде в сайдбаре.
Default: ""
PAPER_ENVIRONMENT_COLOR
Цвет фона бейджа.
Default: ""
PAPER_MENU
Меню.
Default: None
PAPER_MENU_DIVIDER
При встрече указанной строки в списке пунктов PAPER_MENU
,
на её место будут вставлен горизонтальный разделитель.
Default: "-"
PAPER_MENU_PERM_STAFF
Ключевое слово в параметре perms
пункта меню PAPER_MENU
,
которое указывает, что текущий пункт меню должен быть показан
только при условии, что у пользователя установлен флаг is_staff
.
Default: "staff"
PAPER_MENU_PERM_SUPERUSER
Ключевое слово в параметре perms
пункта меню PAPER_MENU
,
которое указывает, что текущий пункт меню должен быть показан
только при условии, что у пользователя установлен флаг is_superuser
.
Default: "superuser"
PAPER_MENU_HIDE_SINGLE_CHILD
При значении True
, те пункты меню, которые содержат единственный
подпункт, не будут отображаться как выпадающие списки. Вместо этого
они сразу будут вести на страницу, указанную в подпункте.
Default: True
PAPER_DEFAULT_TAB_NAME
Алиас вкладки по-умолчанию.
Default: "general"
PAPER_DEFAULT_TAB_TITLE
Заголовок вкладки по-умолчанию.
Default: _("General")
PAPER_LOCALE_PACKAGES
Список модулей, из которых должны загружаться переводы
для JavaScriptCatalog
интерфейса администратора.
Default: ["paper_admin", "django.contrib.admin"]
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for paper_admin-4.4.0-py2.py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 80ba52b998ed726c3ebb619c4053a4543f540f078abe28e5eb22e6fbf7f73c3a |
|
MD5 | 40b889db1ccc77043d9e3f41bf955905 |
|
BLAKE2b-256 | 64328740d18cf7355a1503455fa4052b0004feb94496d49cb62761710870e398 |