Skip to main content

Custom Django admin interface.

Project description

paper-admin

Custom Django admin interface based on Bootstrap 4.

PyPI Build Status Software license

Requirements

  • Python >= 3.7
  • Django >= 3.2

Table of Contents

Installation

Install the latest release with pip:

pip install paper-admin

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_money",     # 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

Some third-party libraries override the standard Django templates and within the paper-admin interface look disfigured. To fix these, you can use the patches included in this package.

The following patches are available:

  • paper_admin.patches.dal
    Fixes the style of the django-autocomplete-light widgets.

  • paper_admin.patches.django_money
    Fixes the style of the django-money widget.

  • paper_admin.patches.django_solo
    Fixes the breadcrumbs in django-solo.

  • paper_admin.patches.mptt
    Adaptation of django-mptt. Adds the ability to sort tree nodes (when the sortable property is specified).

  • paper_admin.patches.logentry_admin
    Fixes the filters and hides unwanted buttons in django-logentry-admin.

  • paper_admin.patches.tree_queries
    Adds the ability to sort tree nodes for django-tree-queries. It is necessary to use the special TreeNodeModelAdmin class instead of the standard 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"
    

To use a patch, you need to add it to the INSTALLED_APPS setting.
Note: as a rule, patches should be added before the libraries they fix.

Badge

Badge is a text description of the environment to prevent confusion between the development and production servers.

The color and text of the badge can be changed in the settings.py file:

PAPER_ENVIRONMENT_NAME = "development"
PAPER_ENVIRONMENT_COLOR = "#FFFF00"

Admin menu

The paper-admin provides a way to create menus in the Django admin interface. It allows you to define a menu tree with items that represent apps, models or custom links. You can also define groups of items and dividers to separate them.

Usage

To use the menu system, you need to define a menu tree in your Django project's settings file. The menu tree is defined as a list of items, where each item can be either a string, a dictionary or an instance of a menu item class.

The following types of menu items are available:

  • Item: Represents a link to a specific URL.
  • Divider: Represents a divider that separates items in the menu.
  • Group: Represents a group of items in the menu.

Here's an example of a simple menu tree:

from django.utils.translation import gettext_lazy as _
from paper_admin.menu import Item, Divider


PAPER_MENU = [
    Item(
        label=_("Dashboard"),
        url="admin:index",
        icon="bi-speedometer2",
    ),
    Divider(),
    Item(
        label=_("Authentication and Authorization"),
        icon="bi-person-circle",
        children=[
            Item(
                model="User",
                icon="bi-lg bi-people",
            ),
            Item(
                model="Group",
                icon="bi-lg bi-people-fill",
            ),
        ]
    )
]

Item

The Item class represents a link to a specific URL. You can use it to create links to Django admin pages, external websites or any other URL.

Properties:

  • app: A string representing the name of the Django app that the menu item will point to. If this is provided, the URL of the menu item will point to the app index page.
  • model: A string representing the name of the Django model that the menu item will point to. If this is provided, the URL of the menu item will point to the model list page.
  • label: A string representing the text that will be displayed in the menu item.
  • url: A string representing the URL that the menu item will point to.
  • icon: The CSS classes to use for the icon of the menu item.
  • perms: A list of permission strings that are required for the user to see this item in the menu. If this property is not provided, the item will be visible to all users.
  • classes: A string of additional CSS classes to add to the menu item.
  • target: The target attribute to use for the link.
  • children: An optional list of Item or Group instances representing sub-items of the menu item.

The app and model parameters cannot be set simultaneously. However, you must specify at least one of the following parameters: app, model, or label.

Example usage:

from django.utils.translation import gettext_lazy as _
from paper_admin.menu import Item


PAPER_MENU = [
    # Menu item with a specified label and URL
    Item(
        label=_("Dashboard"),
        url="admin:index",
        icon="bi-speedometer2",
    ),

    # Menu for the 'auth' app. Child items will be automatically generated
    # from the app's models.
    Item(
        app="auth"
    ),

    # App 'app' with a specified list of models.
    # The app's name is implicitly added to the model names.
    Item(
        app="app",
        icon="bi-house-fill",
        children=[
            Item(
                model="Widgets",
            ),
            Item(
                model="Message",
            ),
            Item(
                model="Book",
            ),
        ]
    ),

    # Specify a model from a specific app as a child item
    Item(
        label=_("Logs"),
        icon="bi-clock-history",
        perms="admin.view_logentry",
        children=[
            Item(
                model="admin.LogEntry",
            ),
        ]
    ),

    # Add CSS classes and a target attribute to a link
    Item(
        label="Google",
        url="https://google.com/",
        icon="bi-google",
        classes="text-warning",
        target="_blank",
    )
]

image

When defining permissions for menu items using the perms parameter, you can use the special values PAPER_MENU_SUPERUSER_PERMISSION (default is superuser) and PAPER_MENU_STAFF_PERMISSION (default is staff) to restrict access to superusers and staff members respectively.

Example:

from paper_admin.menu import Item


PAPER_MENU = [
    Item(
        app="payments",
        icon="bi-money",
        perms=["staff"],
        children=[
            Item(
                model="Payment",
                perms=["superuser"],
            ),
            Item(
                model="Invoice",
            ),
        ]
    ),
]

Divider

The Divider class is used to add a horizontal line to separate items in the menu tree. It doesn't have any properties or methods, it's simply used to visually group items together.

from django.utils.translation import gettext_lazy as _
from paper_admin.menu import Item, Divider


PAPER_MENU = [
    Item(
        label=_("Dashboard"),
        url="#",
    ),
    Divider(),
    Item(
        label=_("About Us"),
        url="#",
    ),
    Item(
        label=_("Blog"),
        url="#",
    ),
    Item(
        label=_("Contacts"),
        url="#",
    ),
    Divider(),
    Item(
        label=_("Users"),
        url="#",
    ),
    Item(
        label=_("Logs"),
        url="#",
    ),
]

image

Group

The Group class represents a group of menu items. It can be used to group related items together under a common heading.

from django.utils.translation import gettext_lazy as _
from paper_admin.menu import Item, Group


PAPER_MENU = [
    Item(
        label=_("Dashboard"),
        url="#",
    ),
    Group(
        label=_("Content"),
        children=[
            Item(
                label=_("About Us"),
                url="#",
            ),
            Item(
                label=_("Blog"),
                url="#",
            ),
        ]
    ),
    Group(
        label=_("Admin Area"),
        perms=["superuser"],
        children=[
            Item(
                label=_("Backups"),
                url="#",
            ),
            Item(
                label=_("Logs"),
                url="#",
            ),
        ]
    ),
]

image

Reorderable drag-and-drop lists

The paper-admin package provides the ability to reorder items in lists using drag-and-drop. To enable this feature, you need to set the sortable property of the model's ModelAdmin to the name of the field that stores the order.

# models.py
from django.db import models


class Company(models.Model):
    # ...
    position = models.IntegerField(
        "position",
        default=0
    )
# admin.py
from django.contrib import admin


class CompanyAdmin(admin.ModelAdmin):
    # ...
    sortable = "position"

https://user-images.githubusercontent.com/6928240/125331456-0f1bb280-e359-11eb-8b17-b04be4b1e62c.mp4


The sorting is performed using AJAX and is saved to the database automatically.

Reorderable inline forms

The paper-admin package also provides the ability to reorder inline forms in the same way. But in this case, the sorting is not saved to the database automatically.

from django.contrib import admin


class StaffInline(admin.StackedInline):
    # ...
    sortable = "position"


class IndustryInline(admin.TabularInline):
    # ...
    sortable = "position"

https://user-images.githubusercontent.com/6928240/125331956-b6004e80-e359-11eb-8422-832dfe37bb6c.mp4


The sorting is compatible with [django-mptt](https://github.com/django-mptt/django-mptt) (if the `paper_admin.patches.mptt` patch is added to `INSTALLED_APPS`). You can only change the order of elements that have the same parent and are at the same level of nesting:

https://user-images.githubusercontent.com/6928240/125340277-55760f00-e363-11eb-94d4-49a978cb7ae4.mp4

Form tabs

The paper-admin provides a way to divide forms into sections. Sections are represented as tabs, which makes it easier to navigate between them.

To use this feature, you need to set the tabs property of the model's ModelAdmin to a list of tab definitions.

from django.contrib import admin
from django.utils.translation import gettext_lazy as _


class TablularInline(admin.TabularInline):
    tab = 'inlines'


@admin.register(Page)
class PageAdmin(admin.ModelAdmin):
    fieldsets = (
        (None, {
            'tab': 'related-fields',
            'fields': (
                # ...
            ),
        }),
        (None, {
            'tab': 'standard-fields',
            'fields': (
                # ...
            )
        }),
        (None, {
            'tab': 'file-fields',
            'fields': (
                # ...
            )
        }),
    )
    tabs = [
        ('related-fields', _('Related fields')),
        ('standard-fields', _('Standard Fields')),
        ('file-fields', _('File Fields')),
        ('inlines', _('Inlines')),
    ]
    inlines = (TablularInline, )

https://user-images.githubusercontent.com/6928240/226703428-c9413de1-42c1-4178-b75f-37412925f18f.mp4


Tabs can also be dynamically generated by the `get_tabs()` method:
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from .models import Page


@admin.register(Page)
class PageAdmin(admin.ModelAdmin):
    def get_tabs(self, request, obj=None):
        return [
            ('general', _('General')),
            ('content', _('Content')),
            ('seo', _('SEO')),
        ]

Form includes

paper-admin provides a convenient way to include custom templates within admin forms at various positions, such as top, middle, or bottom. These positions correspond to different sections of the admin form page.

Each custom form include definition can include the following parameters:

  1. Path to Template (Required): The path to the template you want to include within the form.
  2. Position (Optional): The desired position for the include. It can be one of the following:
    • "top": Above the fieldsets.
    • "middle": Between the fieldsets and inlines.
    • "bottom" (Default): After the inlines.
  3. Tab Name (Optional): If you are using Form tabs, you can specify the name of the tab where the include should be displayed.
from django.contrib import admin
from django.utils.translation import gettext_lazy as _

from ..models import Person


@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    # ...
    tabs = [
        ("general", _("General")),
        ("pets", _("Pets")),
    ]
    form_includes = [
        ("app/includes/disclaimer.html", "top", "general"),
        ("app/includes/privacy_notice.html",),
    ]
<!-- app/includes/privacy_notice.html -->
<div class="paper-card paper-card--info card my-3">
  <div class="card-header">
    <h5 class="card-title mb-0">Privacy notice</h5>
  </div>
  <div class="card-body">
    <small class="text-secondary">
      We use your Personal Data to respond to your enquiries about our services,
      to send you other useful information and to provide our services to you.
    </small>
  </div>
</div>

Result:

image

In addition to the standard way of including custom templates in forms using paper-admin, there's the capability to dynamically create includes using the get_form_includes method. This enables you to flexibly determine which templates to include based on the current request or other conditions.

from django.contrib import admin

from ..models import Person


@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    def get_form_includes(self, request, obj=None):
        if request.user.is_superuser:
            return []

        return [
            ("app/includes/disclaimer.html", "top", "general"),
            ("app/includes/privacy_notice.html",),
        ]

HierarchyFilter

HierarchyFilter is a special type of filter that can be used to filter objects by a hierarchical model field. It is similar to the date_hierarchy filter, but it works with any hierarchical model field.

from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from paper_admin.admin.filters import HierarchyFilter
from .models import Group, Message


class GroupFilter(HierarchyFilter):
    title = _("Group")
    parameter_name = "group"

    def lookups(self, changelist):
        return (
            (pk, name)
            for pk, name in Group.objects.values_list("pk", "name")
        )

    def queryset(self, request, queryset):
        value = self.value()
        if not value:
            return queryset

        return queryset.filter(group__in=value)


@admin.register(Message)
class MessageAdmin(admin.ModelAdmin):
    # ...
    list_filters = [GroupFilter]

Result:

image

Stylization

Table rows

You can use the get_row_classes method of the ModelAdmin class to add custom classes to the rows in the list view.

from django.contrib import admin
from .models import Category


@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):

    def get_row_classes(self, request, obj):
        if obj.status == "success":
            return ["table-success"]
        elif obj.status == "failed":
            return ["table-danger"]
        return []

image

Fieldsets

Django provides a way to add a custom CSS classes to the fieldsets in the admin interface.

To use this feature, specify the classes parameter in the ModelAdmin.fieldsets attribute:

from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from .models import Category


@admin.register(Category)
class CategoryAdmin(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": (
                # ...
            )
        }),
    )

image

Inline forms

You can use the get_form_classes method of the ModelAdmin class to add custom classes to the inline forms:

from django.contrib import admin


class StackedInline(admin.StackedInline):
    def get_form_classes(self, request, obj):
        if obj.status == "success":
            return ["paper-card--success"]
        elif obj.status == "failed":
            return ["paper-card--danger"]
        return []


class TablularInlines(admin.TabularInline):
    def get_form_classes(self, request, obj):
        if obj.status == "success":
            return ["table-success"]
        elif obj.status == "failed":
            return ["table-danger"]
        return []

image image

Settings

PAPER_FAVICON
The path to the favicon for the admin interface.
Default: "paper_admin/dist/assets/default_favicon.png"

PAPER_ENVIRONMENT_NAME
The text of the environment badge.
Default: ""

PAPER_ENVIRONMENT_COLOR
The color of the environment badge.
Default: ""

PAPER_MENU
A list of menu items. See Admin menu for details.
Default: None

PAPER_MENU_DIVIDER
A string representing the menu item divider.
Default: "-"

PAPER_MENU_STAFF_PERMISSION
The special permission string that allows access to the menu item for staff users.
Default: "staff"

PAPER_MENU_SUPERUSER_PERMISSION
The special permission string that allows access to the menu item for superusers.
Default: "superuser"

PAPER_MENU_COLLAPSE_SINGLE_CHILDS
Whether to collapse a menu item if it has only one child.
Default: True

PAPER_DEFAULT_TAB_NAME
The name of the tab to activate in the form by default.
Default: "general"

PAPER_DEFAULT_TAB_TITLE
The title of the tab to activate in the form by default.
Default: _("General")

PAPER_LOCALE_PACKAGES
The list of packages to search for translation strings.
Default: ["paper_admin", "django.contrib.admin"]

PAPER_NONE_PLACEHOLDER
The placeholder text for the "None" option in the filters.
Default:

Additional References

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

paper-admin-7.6.4.tar.gz (3.5 MB view hashes)

Uploaded Source

Built Distribution

paper_admin-7.6.4-py2.py3-none-any.whl (3.5 MB view hashes)

Uploaded Python 2 Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page