Интерфейс администратора Django

One of the most powerful parts of Django is the automatic admin interface. It reads metadata from your models to provide a quick, model-centric interface where trusted users can manage content on your site. The admin’s recommended use is limited to an organization’s internal management tool. It’s not intended for building your entire front end around.

The admin has many hooks for customization, but beware of trying to use those hooks exclusively. If you need to provide a more process-centric interface that abstracts away the implementation details of database tables and fields, then it’s probably time to write your own views.

In this document we discuss how to activate, use, and customize Django’s admin interface.

Обзор

Интерфейс администратора по умолчанию включен, если вы создавали проект командой startproject.

If you’re not using the default project template, here are the requirements:

  1. Add 'django.contrib.admin' and its dependencies - django.contrib.auth, django.contrib.contenttypes, django.contrib.messages, and django.contrib.sessions - to your INSTALLED_APPS setting.
  2. Configure a DjangoTemplates backend in your TEMPLATES setting with django.contrib.auth.context_processors.auth and django.contrib.messages.context_processors.messages in the 'context_processors' option of OPTIONS.
  3. If you’ve customized the MIDDLEWARE setting, django.contrib.auth.middleware.AuthenticationMiddleware and django.contrib.messages.middleware.MessageMiddleware must be included.
  1. Hook the admin’s URLs into your URLconf.

After you’ve taken these steps, you’ll be able to use the admin site by visiting the URL you hooked it into (/admin/, by default).

If you need to create a user to login with, use the createsuperuser command. By default, logging in to the admin requires that the user has the is_superuser or is_staff attribute set to True.

Finally, determine which of your application’s models should be editable in the admin interface. For each of those models, register them with the admin as described in ModelAdmin.

Другие разделы

См.также

Информацию о настройке статических файлов (изображений, JavaScript и CSS) для интерфейса администратора на «боевом» сервере можно найти в разделе Обслуживание файлов.

Вопросы? Обратитесь к FAQ: Админка.

Объект ModelAdmin

class ModelAdmin

The ModelAdmin class is the representation of a model in the admin interface. Usually, these are stored in a file named admin.py in your application. Let’s take a look at an example of the ModelAdmin:

from django.contrib import admin
from myproject.myapp.models import Author

class AuthorAdmin(admin.ModelAdmin):
    pass
admin.site.register(Author, AuthorAdmin)

Нужен ли вообще вам объект ModelAdmin?

В этом примере, класс ModelAdmin не определяет никаких настроек (пока).В результате мы получим интерфейс предоставляемый по умолчанию. Если он вас устраивает, вы можете не определять ModelAdmin совсем и зарегистрировать модель без ModelAdmin. Пример выше может выглядеть таким образом:

from django.contrib import admin
from myproject.myapp.models import Author

admin.site.register(Author)

The register decorator

register(*models, site=django.admin.sites.site)

Существует также декоратор для регистрации ваших классов ModelAdmin:

from django.contrib import admin
from .models import Author

@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
    pass

It’s given one or more model classes to register with the ModelAdmin. If you’re using a custom AdminSite, pass it using the site keyword argument:

from django.contrib import admin
from .models import Author, Editor, Reader
from myproject.admin_site import custom_admin_site

@admin.register(Author, Reader, Editor, site=custom_admin_site)
class PersonAdmin(admin.ModelAdmin):
    pass

You can’t use this decorator if you have to reference your model admin class in its __init__() method, e.g. super(PersonAdmin, self).__init__(*args, **kwargs). You can use super().__init__(*args, **kwargs).

Изучаем файлы админки

При добавлении 'django.contrib.admin' в INSTALLED_APPS setting, Django автоматически ищет модуль admin в каждом приложении и импортирует его.

class apps.AdminConfig

Стандартный класс AppConfig для админки. Вызывает autodiscover() при запуске Django.

class apps.SimpleAdminConfig

Аналогичен AdminConfig, но не вызывает autodiscover().

default_site

A dotted import path to the default admin site’s class or to a callable that returns a site instance. Defaults to 'django.contrib.admin.sites.AdminSite'. See Overriding the default admin site for usage.

autodiscover()

Эта функция пытается импортировать модуль admin каждого установленного приложения. Предполагается, что в этом модуле выполняется регистрация моделей в админке.

Обычно вам не нужно вызывать эту функцию самостоятельно, AdminConfig вызывает её при запуске Django.

Если вы используете собственный AdminSite, вам необходимо импортировать все подклассы ModelAdmin и зарегистрировать их в вашем AdminSite. В этом случае, чтобы отключить их добавление в стандартную админку, используйте 'django.contrib.admin.apps.SimpleAdminConfig' вместо 'django.contrib.admin' в INSTALLED_APPS.

Настройки ModelAdmin

ModelAdmin очень гибкий. Он содержит ряд параметров для настройки интерфейса администратора. Все настройки определяются в подклассе ModelAdmin:

from django.contrib import admin

class AuthorAdmin(admin.ModelAdmin):
    date_hierarchy = 'pub_date'
ModelAdmin.actions

Список действий, которые будут включены на странице списка объектов. Подробности смотрите в разделе Действия администратора.

ModelAdmin.actions_on_top
ModelAdmin.actions_on_bottom

Определяет где на странице будет расположены панели с действиями. По умолчанию эта панель расположена сверху (actions_on_top = True; actions_on_bottom = False).

ModelAdmin.actions_selection_counter

Указывает отображать ли счетчик выбранных объектов после списка действий. По умолчанию он отображается (actions_selection_counter = True).

ModelAdmin.date_hierarchy

Укажите в date_hierarchy название DateField или DateTimeField поля вашей модели, и страница списка объектов будет содержать навигацию по датам из этого поля.

Например:

date_hierarchy = 'pub_date'

You can also specify a field on a related model using the __ lookup, for example:

date_hierarchy = 'author__pub_date'

Навигация учитывает значения поля, например, если все значения будут датами из одного месяца, будут отображаться только дни этого месяца.

Примечание

date_hierarchy использует внутри QuerySet.datetimes(). Обратитесь к описанию, чтобы узнать некоторые нюансы при использовании часовых поясов (USE_TZ = True).

ModelAdmin.empty_value_display

Этот атрибут переопределяет отображение пустого значения записи (None, пустая строка и т.д.). По умолчанию - (дефис). Например:

from django.contrib import admin

class AuthorAdmin(admin.ModelAdmin):
    empty_value_display = '-empty-'

Вы также можете переопределить empty_value_display для всех страниц, указав AdminSite.empty_value_display, или для одного поля:

from django.contrib import admin

class AuthorAdmin(admin.ModelAdmin):
    fields = ('name', 'title', 'view_birth_date')

    def view_birth_date(self, obj):
        return obj.birth_date

    view_birth_date.empty_value_display = '???'
ModelAdmin.exclude

Этот атрибут должен содержать список полей, которые не будут включены в форму редактирования.

Например, у нас есть следующая модель:

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)
    title = models.CharField(max_length=3)
    birth_date = models.DateField(blank=True, null=True)

Если вам необходима форма для модели Author, которая содержит только поля name и title, вы можете определить параметр fields или exclude следующим образом:

from django.contrib import admin

class AuthorAdmin(admin.ModelAdmin):
    fields = ('name', 'title')

class AuthorAdmin(admin.ModelAdmin):
    exclude = ('birth_date',)

Так как модель содержит только три поля, name, title и birth_date, полученные формы будут содержать одинаковые поля.

ModelAdmin.fields

Если вам необходимо внести небольшие изменения форму на странице редактирования и добавления, например, изменить список отображаемых полей, их порядок или сгруппировать их, вы можете использовать настройку fields. Например, необходимо изменить форму модели из приложения django.contrib.flatpages.models.FlatPage:

class FlatPageAdmin(admin.ModelAdmin):
    fields = ('url', 'title', 'content')

В примере выше будут отображаться только поля url, title и content. fields может содержать поля указанные в ModelAdmin.readonly_fields, они не будут доступны для редактирования.

Для более сложных настроек используйте fieldsets.

The fields option accepts the same types of values as list_display, except that callables aren’t accepted. Names of model and model admin methods will only be used if they’re listed in readonly_fields.

Чтобы поля отображались в одной строке, укажите их в кортеже вместе. В этом примере, поля url и title будут отображаться в одном ряду, поле content будет расположено ниже:

class FlatPageAdmin(admin.ModelAdmin):
    fields = (('url', 'title'), 'content')

Примечание

Настройку fields не следует путать с ключом словаря fields в настройке fieldsets, описанной ниже.

Если не определен ни атрибут fields, ни fieldsets, Django покажет все поля с editable=True кроме AutoField, в одном наборе полей в порядке, в котором они указанные в модели.

ModelAdmin.fieldsets

Позволяет изменить макет страниц добавления и редактирования объекта.

fieldsets – это список двух-элементных кортежей, каждый представляет <fieldset> в форме редактирования объекта. (<fieldset> – группа полей в форме.)

Кортеж должен быть в формате (name, options полей), где name это название группы полей, а field_options – словарь с информацией о группе полей, включая список полей для отображения.

Полный пример для модели django.contrib.flatpages.models.FlatPage:

from django.contrib import admin

class FlatPageAdmin(admin.ModelAdmin):
    fieldsets = (
        (None, {
            'fields': ('url', 'title', 'content', 'sites')
        }),
        ('Advanced options', {
            'classes': ('collapse',),
            'fields': ('registration_required', 'template_name'),
        }),
    )

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

../../../_images/fieldsets.png

Если не определен ни атрибут fields, ни fieldsets, Django покажет все поля с editable=True кроме AutoField, в одном наборе полей в порядке, в котором они указанные в модели.

Словарь field_options может содержать следующие ключи:

  • fields

    Кортеж с названиями полей. Этот ключ обязателен.

    Например:

    {
    'fields': ('first_name', 'last_name', 'address', 'city', 'state'),
    }
    

    Как и в атрибуте fields, чтобы отобразить поля в одной строке, добавьте их в один кортеж. В этом примере, поля first_name и last_name будут показаны в одной строке:

    {
    'fields': (('first_name', 'last_name'), 'address', 'city', 'state'),
    }
    

    fields может содержать значения из ModelAdmin.readonly_fields, чтобы отображать поля без возможности их редактирования.

    Добавление функции в fields аналогично добавлению в параметр fields - функция должна быть указанна в readonly_fields.

  • classes

    Список содержащий CSS классы, которые будут добавлены в группу полей.

    Например:

    {
    'classes': ('wide', 'extrapretty'),
    }
    

    Django предоставляет два класса для использования: collapse и wide. Группа полей с классом collapse будет показа в свернутом виде с кнопкой «развернуть». Группа полей с классом wide будет шире по горизонтали.

  • description

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

    Note that this value is not HTML-escaped when it’s displayed in the admin interface. This lets you include HTML if you so desire. Alternatively you can use plain text and django.utils.html.escape() to escape any HTML special characters.

ModelAdmin.filter_horizontal

По умолчанию, поле ManyToManyField отображается как <select multiple>. Однако, это поле тяжело использовать при большом количестве объектов. Добавив ManyToManyField в этот атрибут, будет использоваться «виджет» с JavaScript фильтром для поиска. Смотрите описание filter_vertical про использование вертикального «виджета».

ModelAdmin.filter_vertical

Аналогичен filter_horizontal, но использует вертикальный «виджет».

ModelAdmin.form

По умолчанию ModelForm создается динамически для модели. Этот атрибут используется для определения формы на страницах добавления и редактирования. Вы можете указать собственный подкласс ModelForm для переопределения этих страниц. Вы можете модифицировать форму, а не создавать с нуля свою, переопределив метод ModelAdmin.get_form().

Пример смотрите в разделе Дополнительная проверка данных в интерфейсе администратора.

Примечание

Если вы указали атрибут Meta.model для ModelForm, необходимо также указать Meta.fields (или Meta.exclude). Однако, если поля указаны при определении настроек интерфейса администратора, атрибут Meta.fields будет проигнорирован.

Если ModelForm используется только для интерфейса администратора, проще всего не указывать атрибут Meta.model, т.к. ModelAdmin укажет правильную модель. Вы можете указать fields = [] в Meta чтобы ModelForm была правильной.

Примечание

Если и ModelForm и ModelAdmin определяют опцию exclude, ModelAdmin будет иметь больший приоритет:

from django import forms
from django.contrib import admin
from myapp.models import Person

class PersonForm(forms.ModelForm):

    class Meta:
        model = Person
        exclude = ['name']

class PersonAdmin(admin.ModelAdmin):
    exclude = ['age']
    form = PersonForm

В этом примере, поле «age» не будет добавлено в форму в отличии от поля «name».

ModelAdmin.formfield_overrides

Позволяет быстро изменить настройки отображения различных типов Field в интерфейсе администратора. formfield_overrides – словарь указывающий параметры для классов полей, которые будут передаваться в конструкторы указанных полей.

Все это звучит немного абстрактно, так что давайте рассмотрим пример. Самое распространенное применение formfield_overrides это переопределить «виджет» поля формы. Предположим у нас есть RichTextEditorWidget, который использует расширенное поля редактирования вместо <textarea>. Вот как мы может использовать его:

from django.contrib import admin
from django.db import models

# Import our custom widget and our model from where they're defined
from myapp.models import MyModel
from myapp.widgets import RichTextEditorWidget

class MyModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.TextField: {'widget': RichTextEditorWidget},
    }

Заметим что ключ словаря класс поля, а не строка. Значение это словарь с аргументами. Это аргументы будут переданы в __init__(). Подробности смотрите в разделе API форм.

Предупреждение

If you want to use a custom widget with a relation field (i.e. ForeignKey or ManyToManyField), make sure you haven’t included that field’s name in raw_id_fields, radio_fields, or autocomplete_fields.

formfield_overrides won’t let you change the widget on relation fields that have raw_id_fields, radio_fields, or autocomplete_fields set. That’s because raw_id_fields, radio_fields, and autocomplete_fields imply custom widgets of their own.

ModelAdmin.inlines

Смотрите описание ниже InlineModelAdmin, а также ModelAdmin.get_formsets_with_inlines().

ModelAdmin.list_display

list_display указывает какие поля отображать на странице списка объектов.

Например:

list_display = ('first_name', 'last_name')

If you don’t set list_display, the admin site will display a single column that displays the __str__() representation of each object.

There are four types of values that can be used in list_display:

  • The name of a model field. For example:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'last_name')
    
  • A callable that accepts one argument, the model instance. For example:

    def upper_case_name(obj):
        return ("%s %s" % (obj.first_name, obj.last_name)).upper()
    upper_case_name.short_description = 'Name'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = (upper_case_name,)
    
  • A string representing a ModelAdmin method that accepts one argument, the model instance. For example:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('upper_case_name',)
    
        def upper_case_name(self, obj):
            return ("%s %s" % (obj.first_name, obj.last_name)).upper()
        upper_case_name.short_description = 'Name'
    
  • A string representing a model attribute or method (without any required arguments). For example:

    from django.contrib import admin
    from django.db import models
    
    class Person(models.Model):
        name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        def decade_born_in(self):
            return self.birthday.strftime('%Y')[:3] + "0's"
        decade_born_in.short_description = 'Birth decade'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'decade_born_in')
    

Несколько особенностей list_display:

  • If the field is a ForeignKey, Django will display the __str__() of the related object.

  • ManyToManyField не поддерживается, так как это влечет к созданию SQL запроса для каждого объекта. Если вам необходимо сделать это в любом случае, создайте метод модели и используйте его в list_display. (Смотрите ниже подробности про использование методов в list_display.)

  • If the field is a BooleanField, Django will display a pretty «on» or «off» icon instead of True or False.

  • Если используется метод модели, ModelAdmin или функция, Django по умолчанию экранирует результат. Если вам нужно экранировать данные, вводимые пользователем, и не экранировать собственные теги, используйте format_html().

    Пример:

    from django.contrib import admin
    from django.db import models
    from django.utils.html import format_html
    
    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        color_code = models.CharField(max_length=6)
    
        def colored_name(self):
            return format_html(
                '<span style="color: #{};">{} {}</span>',
                self.color_code,
                self.first_name,
                self.last_name,
            )
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'last_name', 'colored_name')
    
  • As some examples have already demonstrated, when using a callable, a model method, or a ModelAdmin method, you can customize the column’s title by adding a short_description attribute to the callable.

  • Если значение поля None, пустая строка, или пустой итератор, Django покажет - (дефис). Вы можете переопределить это значение с помощью параметра AdminSite.empty_value_display:

    from django.contrib import admin
    
    admin.site.empty_value_display = '(None)'
    

    You can also use ModelAdmin.empty_value_display:

    class PersonAdmin(admin.ModelAdmin):
        empty_value_display = 'unknown'
    

    Или для поля:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'birth_date_view')
    
        def birth_date_view(self, obj):
             return obj.birth_date
    
        birth_date_view.empty_value_display = 'unknown'
    
  • Если используется метод модели, ModelAdmin или функция, которая возвращает True или False, Django покажет «on» или «off» иконки, если вы добавите атрибут boolean методу или функции со значением True.

    Пример:

    from django.contrib import admin
    from django.db import models
    
    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        def born_in_fifties(self):
            return self.birthday.strftime('%Y')[:3] == '195'
        born_in_fifties.boolean = True
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'born_in_fifties')
    
  • The __str__() method is just as valid in list_display as any other model method, so it’s perfectly OK to do this:

    list_display = ('__str__', 'some_other_field')
    
  • Обычно элементы list_display, которые не являются полями модели, не могу быть использованы при сортировке (так как Django выполняет сортировку на уровне базы данных).

    Однако, если элемент list_display представляет определенное поле в базе данных, вы можете указать это добавив атрибут admin_order_field к элементу.

    Например:

    from django.contrib import admin
    from django.db import models
    from django.utils.html import format_html
    
    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        color_code = models.CharField(max_length=6)
    
        def colored_first_name(self):
            return format_html(
                '<span style="color: #{};">{}</span>',
                self.color_code,
                self.first_name,
            )
    
        colored_first_name.admin_order_field = 'first_name'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'colored_first_name')
    

    В этом примере Django будет использовать поле first_name при сортировке по colored_first_name.

    Для обратной сортировки в admin_model_field можно использовать префикс -. Например:

    colored_first_name.admin_order_field = '-first_name'
    

    admin_order_field позволяет добавить сортировку по значению из связанных моделей. Этот пример содержит колонку «имя автора» и позволяет выполнить сортировку по ней:

    class Blog(models.Model):
        title = models.CharField(max_length=255)
        author = models.ForeignKey(Person, on_delete=models.CASCADE)
    
    class BlogAdmin(admin.ModelAdmin):
        list_display = ('title', 'author', 'author_first_name')
    
        def author_first_name(self, obj):
            return obj.author.first_name
    
        author_first_name.admin_order_field = 'author__first_name'
    

    Query expressions may be used in admin_order_field. For example:

    from django.db.models import Value
    from django.db.models.functions import Concat
    
    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
    
        def full_name(self):
            return self.first_name + ' ' + self.last_name
        full_name.admin_order_field = Concat('first_name', Value(' '), 'last_name')
    
  • Elements of list_display can also be properties. Please note however, that due to the way properties work in Python, setting short_description or admin_order_field on a property is only possible when using the property() function and not with the @property decorator.

    Например:

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
    
        def my_property(self):
            return self.first_name + ' ' + self.last_name
        my_property.short_description = "Full name of the person"
        my_property.admin_order_field = 'last_name'
    
        full_name = property(my_property)
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('full_name',)
    
  • Названия полей из list_display будут использованы в CSS классах, форма будет содержать класс column-<field_name> для каждого элемента <th>. Так можно определить ширину полей через CSS стили.

  • Django попытается интерпретировать каждый элемент list_display в следующем порядке:

    • Поле модели.
    • Метод или любой другой вызываемый объект.
    • Строка, представляющая атрибут ModelAdmin.
    • Строка, представляющая атрибут модели.

    Например, если существует поле модели first_name и атрибут ModelAdmin, будет использоваться поле модели.

Используйте list_display_links, чтобы указать какие поля в list_display будут ссылками на страницу редактирования объекта.

По умолчанию, на страницу редактирования объекта будет вести ссылка в первой колонке – первое поле в list_display. Но list_display_links позволяет изменить это поведение:

  • Можно указать None, чтобы убрать ссылки.

  • Укажите список или кортеж полей (так же как и в list_display) чьи колонки должны быть ссылками на страницу редактирования.

    Вы можете указывать одно или несколько полей. Пока указанные поля входят в list_display, Django безразлично сколько их. Единственное требование: для использования list_display_links вы должны указать list_display.

В этом примере поля first_name и last_name будут отображаться как ссылки на страницу редактирования объекта:

class PersonAdmin(admin.ModelAdmin):
    list_display = ('first_name', 'last_name', 'birthday')
    list_display_links = ('first_name', 'last_name')

В этом примере список объектов будет без ссылок:

class AuditEntryAdmin(admin.ModelAdmin):
    list_display = ('timestamp', 'message')
    list_display_links = None
ModelAdmin.list_editable

Укажите в list_editable список полей, которые можно будет редактировать на странице списка объектов. То есть, поля из list_editable будут отображаться как поля формы позволяя пользователям изменять значения и сохранять изменения для всех строк сразу.

Примечание

list_editable взаимодействует с другими настройками следующим образом:

  • Поле из list_editable должно входить в list_display. Вы не можете редактировать поле, которое не отображается!
  • Поле не может быть в list_editable и list_display_links вместе – поле не может быть ссылкой и полем формы.

Вы получите ошибку проверки если нарушите эти правила.

ModelAdmin.list_filter

Укажите list_filter, чтобы определить фильтры данных в правой панели страницы списка объектов, как показано на изображении:

../../../_images/list_filter.png

list_filter - это список элементов, которые могу быть одного из следующих типов:

  • название поля следующего типа: BooleanField, CharField, DateField, DateTimeField, IntegerField, ForeignKey или ManyToManyField. Например:

    class PersonAdmin(admin.ModelAdmin):
        list_filter = ('is_staff', 'company')
    

    Поле в list_filter может указывать и на связанный объект используя __, например:

    class PersonAdmin(admin.UserAdmin):
        list_filter = ('company__name',)
    
  • подкласс django.contrib.admin.SimpleListFilter, в котором необходимо определить атрибуты title и parameter_name и переопределить методы lookups и queryset, например:

    from datetime import date
    
    from django.contrib import admin
    from django.utils.translation import gettext_lazy as _
    
    class DecadeBornListFilter(admin.SimpleListFilter):
        # Human-readable title which will be displayed in the
        # right admin sidebar just above the filter options.
        title = _('decade born')
    
        # Parameter for the filter that will be used in the URL query.
        parameter_name = 'decade'
    
        def lookups(self, request, model_admin):
            """
            Returns a list of tuples. The first element in each
            tuple is the coded value for the option that will
            appear in the URL query. The second element is the
            human-readable name for the option that will appear
            in the right sidebar.
            """
            return (
                ('80s', _('in the eighties')),
                ('90s', _('in the nineties')),
            )
    
        def queryset(self, request, queryset):
            """
            Returns the filtered queryset based on the value
            provided in the query string and retrievable via
            `self.value()`.
            """
            # Compare the requested value (either '80s' or '90s')
            # to decide how to filter the queryset.
            if self.value() == '80s':
                return queryset.filter(birthday__gte=date(1980, 1, 1),
                                        birthday__lte=date(1989, 12, 31))
            if self.value() == '90s':
                return queryset.filter(birthday__gte=date(1990, 1, 1),
                                        birthday__lte=date(1999, 12, 31))
    
    class PersonAdmin(admin.ModelAdmin):
        list_filter = (DecadeBornListFilter,)
    

    Примечание

    Для удобства объект HttpRequest передается в методы lookups и queryset, например:

    class AuthDecadeBornListFilter(DecadeBornListFilter):
    
        def lookups(self, request, model_admin):
            if request.user.is_superuser:
                return super().lookups(request, model_admin)
    
        def queryset(self, request, queryset):
            if request.user.is_superuser:
                return super().queryset(request, queryset)
    

    Также объект ModelAdmin передается в метод lookups. Например, вы можете использовать существующие данные при создании фильтра:

    class AdvancedDecadeBornListFilter(DecadeBornListFilter):
    
        def lookups(self, request, model_admin):
            """
            Only show the lookups if there actually is
            anyone born in the corresponding decades.
            """
            qs = model_admin.get_queryset(request)
            if qs.filter(birthday__gte=date(1980, 1, 1),
                          birthday__lte=date(1989, 12, 31)).exists():
                yield ('80s', _('in the eighties'))
            if qs.filter(birthday__gte=date(1990, 1, 1),
                          birthday__lte=date(1999, 12, 31)).exists():
                yield ('90s', _('in the nineties'))
    
  • кортеж, где первый элемент название поля, а второй - подкласс django.contrib.admin.FieldListFilter, например:

    class PersonAdmin(admin.ModelAdmin):
        list_filter = (
            ('is_staff', admin.BooleanFieldListFilter),
        )
    

    You can limit the choices of a related model to the objects involved in that relation using RelatedOnlyFieldListFilter:

    class BookAdmin(admin.ModelAdmin):
        list_filter = (
            ('author', admin.RelatedOnlyFieldListFilter),
        )
    

    Предположим author это ForeignKey к модели User, это ограничит выбор в list_filter пользователями, которые написали книгу, вместо всех пользователей.

    Примечание

    API FieldListFilter считается внутренним и может быть изменено.

List filter’s typically appear only if the filter has more than one choice. A filter’s has_output() method controls whether or not it appears.

Вы можете указать собственный шаблон для отображения фильтра:

class FilterWithCustomTemplate(admin.SimpleListFilter):
    template = "custom_template.html"

See the default template provided by Django (admin/filter.html) for a concrete example.

ModelAdmin.list_max_show_all

Используйте list_max_show_all, чтобы указать количество объектов на странице списка объектов при выборе «Показать все». Интерфейс администратора покажет ссылку «Показать все» только если общее количество объектов меньше или равно этому значению. По умолчанию равно 200.

ModelAdmin.list_per_page

Используйте list_per_page, чтобы определить количество объектов на одной странице при отображении списка объектов. По умолчанию равно 100.

Используйте list_select_related, чтобы указать Django использовать select_related() при выборе объектов для страницы отображения объектов. Это может сократить количество запросов на этой странице.

Значение должно быть булево, список или кортеж. По умолчанию равно False.

При True, select_related() всегда будет использоваться. При False, Django найдет в list_display все ForeignKey и будет использовать их с select_related().

Если вам нужен больший контроль, используйте список или кортеж для list_select_related. Пустой кортеж укажет не использовать select_related. Не пустой кортеж будет передан как параметр для select_related. Например:

class ArticleAdmin(admin.ModelAdmin):
    list_select_related = ('author', 'category')

вызовет select_related('author', 'category').

Если вам необходимы динамические значения, которые зависят от текущего запроса, вы можете определить метод get_list_select_related().

Примечание

ModelAdmin ignores this attribute when select_related() was already called on the changelist’s QuerySet.

ModelAdmin.ordering

ordering позволяет определить сортировку на странице списка объектов. Это должен быть список или кортеж в формате аналогичном параметру ordering.

Если атрибут не указана, Django будет использовать сортировку по умолчанию модели.

Если вам необходима динамическая сортировка (например, в зависимости от пользователя или текущего языка) вы можете определить метод get_ordering().

Performance considerations with ordering and sorting

To ensure a deterministic ordering of results, the changelist adds pk to the ordering if it can’t find a single or unique together set of fields that provide total ordering.

For example, if the default ordering is by a non-unique name field, then the changelist is sorted by name and pk. This could perform poorly if you have a lot of rows and don’t have an index on name and pk.

ModelAdmin.paginator

Класс, используемый для создания постраничного отображения. По умолчанию используется django.core.paginator.Paginator. Если конструктор вашего класса принимает параметры отличные от django.core.paginator.Paginator, вам необходимо также переопределить метод ModelAdmin.get_paginator().

ModelAdmin.prepopulated_fields

prepopulated_fields позволяет определить поля, которые получают значение основываясь на значениях других полей:

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

When set, the given fields will use a bit of JavaScript to populate from the fields assigned. The main use for this functionality is to automatically generate the value for SlugField fields from one or more other fields. The generated value is produced by concatenating the values of the source fields, and then by transforming that result into a valid slug (e.g. substituting dashes for spaces; lowercasing ASCII letters; and removing various English stop words such as „a“, „an“, „as“, and similar).

Prepopulated fields aren’t modified by JavaScript after a value has been saved. It’s usually undesired that slugs change (which would cause an object’s URL to change if the slug is used in it).

prepopulated_fields doesn’t accept DateTimeField, ForeignKey, OneToOneField, and ManyToManyField fields.

ModelAdmin.preserve_filters

Интерфейс администратора сохраняет состояние фильтров после создания, редактирования и удаления объектов. Чтобы отключить это поведение, используйте False.

ModelAdmin.radio_fields

По умолчанию Django использует <select> для полей ForeignKey или тех, которые содержат choices. Ели поле указанно в radio_fields, Django будет использовать радио кнопки. Предположим что group поле ForeignKey в модели Person:

class PersonAdmin(admin.ModelAdmin):
    radio_fields = {"group": admin.VERTICAL}

Вы можете использовать HORIZONTAL или VERTICAL из модуля django.contrib.admin.

Не добавляйте в radio_fields поля, которые не являются ForeignKey или не содержат choices.

ModelAdmin.autocomplete_fields

autocomplete_fields is a list of ForeignKey and/or ManyToManyField fields you would like to change to Select2 autocomplete inputs.

By default, the admin uses a select-box interface (<select>) for those fields. Sometimes you don’t want to incur the overhead of selecting all the related instances to display in the dropdown.

The Select2 input looks similar to the default input but comes with a search feature that loads the options asynchronously. This is faster and more user-friendly if the related model has many instances.

You must define search_fields on the related object’s ModelAdmin because the autocomplete search uses it.

To avoid unauthorized data disclosure, users must have the view or change permission to the related object in order to use autocomplete.

Ordering and pagination of the results are controlled by the related ModelAdmin’s get_ordering() and get_paginator() methods.

In the following example, ChoiceAdmin has an autocomplete field for the ForeignKey to the Question. The results are filtered by the question_text field and ordered by the date_created field:

class QuestionAdmin(admin.ModelAdmin):
    ordering = ['date_created']
    search_fields = ['question_text']

class ChoiceAdmin(admin.ModelAdmin):
    autocomplete_fields = ['question']

Performance considerations for large datasets

Ordering using ModelAdmin.ordering may cause performance problems as sorting on a large queryset will be slow.

Also, if your search fields include fields that aren’t indexed by the database, you might encounter poor performance on extremely large tables.

For those cases, it’s a good idea to write your own ModelAdmin.get_search_results() implementation using a full-text indexed search.

You may also want to change the Paginator on very large tables as the default paginator always performs a count() query. For example, you could override the default implementation of the Paginator.count property.

ModelAdmin.raw_id_fields

По умолчанию Django использует <select> для полей ForeignKey. Если связанных объектов очень много, создание <select> может быть очень затратным процессом.

raw_id_fields содержит список полей, которые будут использовать поле Input для ForeignKey или ManyToManyField:

class ArticleAdmin(admin.ModelAdmin):
    raw_id_fields = ("newspaper",)

Виджет поля для raw_id_fields будет содержать значение первичного ключа для ForeignKey или список ключей для ManyToManyField. Возле поля есть кнопка поиска и выбора связанных объектов:

../../../_images/raw_id_fields.png
ModelAdmin.readonly_fields

По умолчанию интерфейс администратора отображает все поля как редактируемые. Поля указанные в этой настройке (которая является list или tuple) будут отображаться значение без возможности редактировать, они также будут исключены из ModelForm используемой для создания и редактирования объектов. Однако, если вы определяете аргумент ModelAdmin.fields или ModelAdmin.fieldsets поля для чтения должны быть в них указаны (иначе они будут проигнорированы).

Если readonly_fields используется без определения порядка полей через атрибуты ModelAdmin.fields или ModelAdmin.fieldsets, поля из этой настройки будут отображаться после редактируемых полей.

A read-only field can not only display data from a model’s field, it can also display the output of a model’s method or a method of the ModelAdmin class itself. This is very similar to the way ModelAdmin.list_display behaves. This provides a way to use the admin interface to provide feedback on the status of the objects being edited, for example:

from django.contrib import admin
from django.utils.html import format_html_join
from django.utils.safestring import mark_safe

class PersonAdmin(admin.ModelAdmin):
    readonly_fields = ('address_report',)

    def address_report(self, instance):
        # assuming get_full_address() returns a list of strings
        # for each line of the address and you want to separate each
        # line by a linebreak
        return format_html_join(
            mark_safe('<br>'),
            '{}',
            ((line,) for line in instance.get_full_address()),
        ) or mark_safe("<span class='errors'>I can't determine this address.</span>")

    # short_description functions like a model field's verbose_name
    address_report.short_description = "Address"
ModelAdmin.save_as

Set save_as to enable a «save as new» feature on admin change forms.

Normally, objects have three save options: «Save», «Save and continue editing», and «Save and add another». If save_as is True, «Save and add another» will be replaced by a «Save as new» button that creates a new object (with a new ID) rather than updating the existing object.

По умолчанию save_as равен False.

ModelAdmin.save_as_continue

When save_as=True, the default redirect after saving the new object is to the change view for that object. If you set save_as_continue=False, the redirect will be to the changelist view.

By default, save_as_continue is set to True.

ModelAdmin.save_on_top

Укажите save_on_top, чтобы добавить кнопки сохранения в верхней части страницы редактирования объекта.

По умолчанию кнопки сохранения отображаются под формой. Если указать save_on_top, кнопки будут отображаться и сверху и снизу.

По умолчанию save_on_top равен False.

ModelAdmin.search_fields

search_fields позволяет добавить поиск на страницу списка объектов. Этот атрибут должен содержать список полей, которые будут использоваться при поиске.

Эти поля должны быть текстовыми, таким как CharField или TextField. Вы можете указать поля из связанных объектов используя __:

search_fields = ['foreign_key__related_fieldname']

Например, у нас есть модель записи в блоге с полем автора. Следующая настройка позволит искать записи по email адресу автора:

search_fields = ['user__email']

When somebody does a search in the admin search box, Django splits the search query into words and returns all objects that contain each of the words, case-insensitive (using the icontains lookup), where each word must be in at least one of search_fields. For example, if search_fields is set to ['first_name', 'last_name'] and a user searches for john lennon, Django will do the equivalent of this SQL WHERE clause:

WHERE (first_name ILIKE '%john%' OR last_name ILIKE '%john%')
AND (first_name ILIKE '%lennon%' OR last_name ILIKE '%lennon%')

If you don’t want to use icontains as the lookup, you can use any lookup by appending it the field. For example, you could use exact by setting search_fields to ['first_name__exact'].

Beware that because query terms are split and ANDed as described earlier, searching with exact only works with a single search word since two or more words can’t all be an exact match unless all words are the same.

Some (older) shortcuts for specifying a field lookup are also available. You can prefix a field in search_fields with the following characters and it’s equivalent to adding __<lookup> to the field:

Prefix Lookup
^ startswith
= iexact
@ search
None icontains

Вы можете переопределить метод ModelAdmin.get_search_results(), чтобы указать дополнительные параметры при поиске, или переопределить механизм поиска.

ModelAdmin.show_full_result_count

show_full_result_count указывает показывать ли количество всех объектов при фильтрации (например 99 results (103 total)). Если опция равна False, будет показан подобный текст: 99 results (Show all).

По умолчанию show_full_result_count=True выполняет запрос, чтобы получить количество всех объектов, что может работать очень медленно для таблиц с большим количеством данных.

ModelAdmin.sortable_by

By default, the change list page allows sorting by all model fields (and callables that have the admin_order_field property) specified in list_display.

If you want to disable sorting for some columns, set sortable_by to a collection (e.g. list, tuple, or set) of the subset of list_display that you want to be sortable. An empty collection disables sorting for all columns.

If you need to specify this list dynamically, implement a get_sortable_by() method instead.

ModelAdmin.view_on_site

view_on_site определять показывать ли ссылку «Посмотреть на сайте». Эта ссылка должна вести на страницу сохраненного объекта.

Можно указать булево или функцию. При True (по умолчанию) будет использоваться метод get_absolute_url() объекта для получения ссылки.

Если модель содержит метод get_absolute_url(), но вы не хотите показывать кнопку «Посмотреть на сайте», укажите False в view_on_site:

from django.contrib import admin

class PersonAdmin(admin.ModelAdmin):
    view_on_site = False

Можно указать функцию, которая принимает один аргумент - объект модели. Например:

from django.contrib import admin
from django.urls import reverse

class PersonAdmin(admin.ModelAdmin):
    def view_on_site(self, obj):
        url = reverse('person-detail', kwargs={'slug': obj.slug})
        return 'https://example.com' + url

Настройки шаблонов

Раздел Переопределение шаблонов в интерфейсе администратора описывает как переопределить или расширить шаблоны интерфейса администратора. Используйте следующие настройки, чтобы переопределить шаблоны, которые используются представлениями ModelAdmin:

ModelAdmin.add_form_template

Путь к шаблону, который используется add_view().

ModelAdmin.change_form_template

Путь к шаблону, который используется change_view().

ModelAdmin.change_list_template

Путь к шаблону, который используется changelist_view().

ModelAdmin.delete_confirmation_template

Путь к шаблону, который используется delete_view() для отображения страницы подтверждения удаления одного или нескольких объектов.

ModelAdmin.delete_selected_confirmation_template

Путь к шаблону, который используется delete_selected для отображения страницы подтверждения удаления одного или нескольких объектов. Подробности смотрите в разделе о действиях в интерфейсе администратора.

ModelAdmin.object_history_template

Путь к шаблону, который используется history_view().

ModelAdmin.popup_response_template

Path to a custom template, used by response_add(), response_change(), and response_delete().

Методы ModelAdmin

Предупреждение

When overriding ModelAdmin.save_model() and ModelAdmin.delete_model(), your code must save/delete the object. They aren’t meant for veto purposes, rather they allow you to perform extra operations.

ModelAdmin.save_model(request, obj, form, change)

The save_model method is given the HttpRequest, a model instance, a ModelForm instance, and a boolean value based on whether it is adding or changing the object. Overriding this method allows doing pre- or post-save operations. Call super().save_model() to save the object using Model.save().

Например, добавление request.user к объекту перед сохранением объекта:

from django.contrib import admin

class ArticleAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.user = request.user
        super().save_model(request, obj, form, change)
ModelAdmin.delete_model(request, obj)

The delete_model method is given the HttpRequest and a model instance. Overriding this method allows doing pre- or post-delete operations. Call super().delete_model() to delete the object using Model.delete().

ModelAdmin.delete_queryset(request, queryset)

The delete_queryset() method is given the HttpRequest and a QuerySet of objects to be deleted. Override this method to customize the deletion process for the «delete selected objects» action.

ModelAdmin.save_formset(request, form, formset, change)

Метод save_formset принимает объект HttpRequest, ModelForm родительского объекта, «formset» связанных объектов и булево значение указывающее создан родительский объект или изменяется.

Например, добавление request.user к каждому объекту, измененному в наборе форм:

class ArticleAdmin(admin.ModelAdmin):
    def save_formset(self, request, form, formset, change):
        instances = formset.save(commit=False)
        for obj in formset.deleted_objects:
            obj.delete()
        for instance in instances:
            instance.user = request.user
            instance.save()
        formset.save_m2m()

Смотрите также Сохранение объектов набора форм.

ModelAdmin.get_ordering(request)

Метод get_ordering принимает объект request и должен вернуть list или tuple с параметрами сортировки аналогично атрибуту ordering. Например:

class PersonAdmin(admin.ModelAdmin):

    def get_ordering(self, request):
        if request.user.is_superuser:
            return ['name', 'rank']
        else:
            return ['name']
ModelAdmin.get_search_results(request, queryset, search_term)

Метод get_search_results фильтрует список объектов в соответствии с параметрами поиска. Он принимает запрос, queryset объектов, и параметры поиска указанные пользователем. Возвращает кортеж содержащий полученный queryset и булево указывающее может ли результат содержать одинаковые значения.

По умолчанию выполняется поиск по полям из ModelAdmin.search_fields.

Вы можете переопределить это метод поменяв механизм поиска. Например, вы можете искать по численным полям, или использовать поисковый движок, такой как Solr или Haystack. Вы должны определять наличие дубликатов в результате поиска и возвращать True вторым элементом результата.

For example, to search by name and age, you could use:

class PersonAdmin(admin.ModelAdmin):
    list_display = ('name', 'age')
    search_fields = ('name',)

    def get_search_results(self, request, queryset, search_term):
        queryset, use_distinct = super().get_search_results(request, queryset, search_term)
        try:
            search_term_as_int = int(search_term)
        except ValueError:
            pass
        else:
            queryset |= self.model.objects.filter(age=search_term_as_int)
        return queryset, use_distinct

This implementation is more efficient than search_fields = ('name', '=age') which results in a string comparison for the numeric field, for example ... OR UPPER("polls_choice"."votes"::text) = UPPER('4') on PostgreSQL.

Метод save_related принимает объект HttpRequest, родительскую форму ModelForm, список «inline formsets» и булево значение указывающее создан родительский объект или изменяется. Вы можете выполнить дополнительные операции перед и после сохранения объектов. Заметим, что к этому моменту родительский объект и его формы уже будут сохранены.

ModelAdmin.get_autocomplete_fields(request)

The get_autocomplete_fields() method is given the HttpRequest and is expected to return a list or tuple of field names that will be displayed with an autocomplete widget as described above in the ModelAdmin.autocomplete_fields section.

ModelAdmin.get_readonly_fields(request, obj=None)

Метод get_readonly_fields принимает объект HttpRequest и редактируемый объект obj (или None для формы создания нового объекта) и должен вернуть list или tuple содержащий список полей, которые будут отображаться только для чтения как описано в разделе ModelAdmin.readonly_fields.

ModelAdmin.get_prepopulated_fields(request, obj=None)

Метод get_prepopulated_fields принимает объект HttpRequest и редактируемый объект obj (или None для формы создания нового объекта) и должен вернуть словарь полей аналогичный ModelAdmin.prepopulated_fields.

ModelAdmin.get_list_display(request)

Метод get_list_display принимает объект HttpRequest и редактируемый объект obj (или None для формы создания нового объекта) и должен вернуть list или tuple содержащий список полей, которые будут отображаться на странице списка объектов как описано в разделе ModelAdmin.list_display.

Метод get_list_display_links принимает объект HttpRequest и list или tuple указанный в ModelAdmin.get_list_display(). Должен вернуть None, list или tuple содержащий список полей, который будут ссылками на странице списка объектов к странице редактирования. Смотрите описание ModelAdmin.list_display_links.

ModelAdmin.get_exclude(request, obj=None)

The get_exclude method is given the HttpRequest and the obj being edited (or None on an add form) and is expected to return a list of fields, as described in ModelAdmin.exclude.

ModelAdmin.get_fields(request, obj=None)

Метод get_fields принимает объект HttpRequest и редактируемый объект obj (или None для формы создания нового объекта) и должен вернуть список полей аналогичный ModelAdmin.fields.

ModelAdmin.get_fieldsets(request, obj=None)

Метод get_fieldsets принимает объект HttpRequest и редактируемый объект obj (или None для формы создания нового объекта) и должен вернуть список двухэлементных кортежей, которые определяют <fieldset> формы, как было описано выше в разделе про ModelAdmin.fieldsets.

ModelAdmin.get_list_filter(request)

Метод get_list_filter принимает HttpRequest должен вернуть значение формата, соответствующего параметру list_filter.

Метод get_list_select_related принимает HttpRequest должен вернуть значение формата, соответствующего параметру list_filter.

ModelAdmin.get_search_fields(request)

Метод get_search_fields принимает HttpRequest должен вернуть значение формата, соответствующего параметру search_fields.

ModelAdmin.get_sortable_by(request)

The get_sortable_by() method is passed the HttpRequest and is expected to return a collection (e.g. list, tuple, or set) of field names that will be sortable in the change list page.

Its default implementation returns sortable_by if it’s set, otherwise it defers to get_list_display().

For example, to prevent one or more columns from being sortable:

class PersonAdmin(admin.ModelAdmin):

    def get_sortable_by(self, request):
        return {*self.get_list_display(request)} - {'rank'}
ModelAdmin.get_inline_instances(request, obj=None)

The get_inline_instances method is given the HttpRequest and the obj being edited (or None on an add form) and is expected to return a list or tuple of InlineModelAdmin objects, as described below in the InlineModelAdmin section. For example, the following would return inlines without the default filtering based on add, change, delete, and view permissions:

class MyModelAdmin(admin.ModelAdmin):
    inlines = (MyInline,)

    def get_inline_instances(self, request, obj=None):
        return [inline(self.model, self.admin_site) for inline in self.inlines]

Если вы переопределяете этот метод, убедитесь, что возвращаемы объекты являются экземплярами одного из классов из inlines, иначе можете получить ошибку «Bad Request» при добавлении связанного объекта.

ModelAdmin.get_inlines(request, obj)
New in Django 3.0.

The get_inlines method is given the HttpRequest and the obj being edited (or None on an add form) and is expected to return an iterable of inlines. You can override this method to dynamically add inlines based on the request or model instance instead of specifying them in ModelAdmin.inlines.

ModelAdmin.get_urls()

Метод get_urls класса ModelAdmin возвращает URL-ы, которые используются для ModelAdmin в URLconf. Вы можете дополнить их как описано в Менеджер URL-ов:

from django.contrib import admin
from django.template.response import TemplateResponse
from django.urls import path

class MyModelAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super().get_urls()
        my_urls = [
            path('my_view/', self.my_view),
        ]
        return my_urls + urls

    def my_view(self, request):
        # ...
        context = dict(
           # Include common variables for rendering the admin template.
           self.admin_site.each_context(request),
           # Anything else you want in the context...
           key=value,
        )
        return TemplateResponse(request, "sometemplate.html", context)

Вы можете использовать базовый шаблон админки admin/base_site.html:

{% extends "admin/base_site.html" %}
{% block content %}
...
{% endblock %}

Примечание

Заметим, что собственные URL-шаблоны включаются перед URL-шаблонами интерфейса администратора, которые удовлетворяют почти всем URL-ам. Поэтому желательно добавлять собственные URL-шаблоны перед встроенными.

В этом примере, представление my_view будет доступно по ссылке /admin/myapp/mymodel/my_view/ (предполагается что вы добавили URL-ы интерфейса администратора к /admin/.)

Однако, есть несколько проблем, связанных с функцией self.my_view:

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

Обычно это не то, что вам нужно, Django предоставляет функцию-обертку для проверки прав и отключения кэширования. Эта функция – AdminSite.admin_view() (или self.admin_site.admin_view в методе ModelAdmin). Используйте ее следующим образом:

class MyModelAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super().get_urls()
        my_urls = [
            path('my_view/', self.admin_site.admin_view(self.my_view))
        ]
        return my_urls + urls

Обратите внимание на следующую строку:

path('my_view/', self.admin_site.admin_view(self.my_view))

Функция-обертка защищает self.my_view от несанкционированного доступа и применяет декоратор django.views.decorators.cache.never_cache для предотвращения кэширования, если промежуточный слой кэширования активирован.

Если страницу необходимо кэшировать, но необходимо проверять авторизацию, вы можете использовать аргумент cacheable=True для AdminSite.admin_view:

path('my_view/', self.admin_site.admin_view(self.my_view, cacheable=True))

Представления ModelAdmin содержат атрибуты model_admin. Другие представления AdminSite содержат атрибут admin_site.

ModelAdmin.get_form(request, obj=None, **kwargs)

Возвращает класс ModelForm используемый при добавлении и редактировании объектов, смотрите описание add_view() и change_view().

Базовая реализация использует modelform_factory() для создания form с измененными параметрами fields и exclude. Поэтому, если вы, например, захотите добавить поля форме для суперпользователя, вы можете изменить базовый класс формы:

class MyModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        if request.user.is_superuser:
            kwargs['form'] = MySuperuserForm
        return super().get_form(request, obj, **kwargs)

You may also return a custom ModelForm class directly.

ModelAdmin.get_formsets_with_inlines(request, obj=None)

Выполняет yield по парам (FormSet, InlineModelAdmin), чтобы вернуть набор форм для страницы создания и изменения.

Например, если некоторый «inline» необходимо отображать только при редактировании, можно переопределить метод get_formsets_with_inlines:

class MyModelAdmin(admin.ModelAdmin):
    inlines = [MyInline, SomeOtherInline]

    def get_formsets_with_inlines(self, request, obj=None):
        for inline in self.get_inline_instances(request, obj):
            # hide MyInline in the add view
            if not isinstance(inline, MyInline) or obj is not None:
                yield inline.get_formset(request, obj), inline
ModelAdmin.formfield_for_foreignkey(db_field, request, **kwargs)

Метод formfield_for_foreignkey позволяет вам переопределить поле для внешнего ключа. Например, изменить выбор объектов в зависимости от пользователя:

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "car":
            kwargs["queryset"] = Car.objects.filter(owner=request.user)
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

Объект HttpRequest используется, чтобы отфильтровать для выбора объекты модели Car по текущему пользователю.

ModelAdmin.formfield_for_manytomany(db_field, request, **kwargs)

Как и метод formfield_for_foreignkey, formfield_for_manytomany позволяет переопределить поле формы для связей многое-ко-многим. Например, если пользователь может владеть несколькими машинами и машина может принадлежать нескольким пользователям, вы можете отфильтровать модель Car, чтобы отображать машины только текущего пользователя:

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_manytomany(self, db_field, request, **kwargs):
        if db_field.name == "cars":
            kwargs["queryset"] = Car.objects.filter(owner=request.user)
        return super().formfield_for_manytomany(db_field, request, **kwargs)
ModelAdmin.formfield_for_choice_field(db_field, request, **kwargs)

Как и методы formfield_for_foreignkey и formfield_for_manytomany, formfield_for_choice_field позволяет переопределить поле формы для поля модели, которое содержит choices. Например, если главному администратору необходимо отображать варианты значений отличные от вариантов ответов для остальных пользователей:

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_choice_field(self, db_field, request, **kwargs):
        if db_field.name == "status":
            kwargs['choices'] = (
                ('accepted', 'Accepted'),
                ('denied', 'Denied'),
            )
            if request.user.is_superuser:
                kwargs['choices'] += (('ready', 'Ready for deployment'),)
        return super().formfield_for_choice_field(db_field, request, **kwargs)

Примечание

Атрибут choices, указанный в поле форме, влияет только на проверку поля формы. Если соответствующее поле модели содержит choices, choices в поле формы должен быть его подмножеством, иначе вы получите ValidationError при проверке модели.

ModelAdmin.get_changelist(request, **kwargs)

Возвращает класс Changelist, который используется для отображения списка объекта. По умолчанию, используется django.contrib.admin.views.main.ChangeList. Унаследовав этот класс вы можете переопределить поведение этой страницы.

ModelAdmin.get_changelist_form(request, **kwargs)

Возвращает подкласс ModelForm для Formset, который будет использоваться на странице списка объектов. Например:

from django import forms

class MyForm(forms.ModelForm):
    pass

class MyModelAdmin(admin.ModelAdmin):
    def get_changelist_form(self, request, **kwargs):
        return MyForm

Примечание

Meta.model

ModelAdmin.get_changelist_formset(request, **kwargs)

Возвращает ModelFormSet, который будет использоваться на странице списка объектов, если включен list_editable. Например:

from django.forms import BaseModelFormSet

class MyAdminFormSet(BaseModelFormSet):
    pass

class MyModelAdmin(admin.ModelAdmin):
    def get_changelist_formset(self, request, **kwargs):
        kwargs['formset'] = MyAdminFormSet
        return super().get_changelist_formset(request, **kwargs)
ModelAdmin.lookup_allowed(lookup, value)

The objects in the changelist page can be filtered with lookups from the URL’s query string. This is how list_filter works, for example. The lookups are similar to what’s used in QuerySet.filter() (e.g. user__email=user@example.com). Since the lookups in the query string can be manipulated by the user, they must be sanitized to prevent unauthorized data exposure.

The lookup_allowed() method is given a lookup path from the query string (e.g. 'user__email') and the corresponding value (e.g. 'user@example.com'), and returns a boolean indicating whether filtering the changelist’s QuerySet using the parameters is permitted. If lookup_allowed() returns False, DisallowedModelAdminLookup (subclass of SuspiciousOperation) is raised.

By default, lookup_allowed() allows access to a model’s local fields, field paths used in list_filter (but not paths from get_list_filter()), and lookups required for limit_choices_to to function correctly in raw_id_fields.

Override this method to customize the lookups permitted for your ModelAdmin subclass.

ModelAdmin.has_view_permission(request, obj=None)

Should return True if viewing obj is permitted, False otherwise. If obj is None, should return True or False to indicate whether viewing of objects of this type is permitted in general (e.g., False will be interpreted as meaning that the current user is not permitted to view any object of this type).

The default implementation returns True if the user has either the «change» or «view» permission.

ModelAdmin.has_add_permission(request)

Должен возвращать True, если пользователю позволено добавлять новый объект, иначе False.

ModelAdmin.has_change_permission(request, obj=None)

Should return True if editing obj is permitted, False otherwise. If obj is None, should return True or False to indicate whether editing of objects of this type is permitted in general (e.g., False will be interpreted as meaning that the current user is not permitted to edit any object of this type).

ModelAdmin.has_delete_permission(request, obj=None)

Should return True if deleting obj is permitted, False otherwise. If obj is None, should return True or False to indicate whether deleting objects of this type is permitted in general (e.g., False will be interpreted as meaning that the current user is not permitted to delete any object of this type).

ModelAdmin.has_module_permission(request)

Should return True if displaying the module on the admin index page and accessing the module’s index page is permitted, False otherwise. Uses User.has_module_perms() by default. Overriding it does not restrict access to the view, add, change, or delete views, has_view_permission(), has_add_permission(), has_change_permission(), and has_delete_permission() should be used for that.

ModelAdmin.get_queryset(request)

Метод get_queryset возвращает QuerySet всех объектов модели, которые можно редактировать в интерфейсе администратора. Этот метод можно использовать для отображения объектов принадлежащих текущему пользователю:

class MyModelAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        qs = super().get_queryset(request)
        if request.user.is_superuser:
            return qs
        return qs.filter(author=request.user)
ModelAdmin.message_user(request, message, level=messages.INFO, extra_tags='', fail_silently=False)

Отправляет сообщение пользователю используя django.contrib.messages. Смотрите пример переопределения ModelAdmin.

Аргументы позволят изменить тип сообщения, добавить дополнительные CSS теги, или указать игнорировать ошибку, если contrib.messages не установлен. Эти аргументы совпадают с аргументами django.contrib.messages.add_message(). Единственное отличие - тип сообщения можно указать строкой, а не только числом или константой.

ModelAdmin.get_paginator(request, queryset, per_page, orphans=0, allow_empty_first_page=True)

Возвращает объект для постраничного отображения. По умолчанию возвращает объект paginator.

ModelAdmin.response_add(request, obj, post_url_continue=None)

Указывает HttpResponse для add_view().

response_add вызывается поле отправки формы и после сохранения объекта и всех связанных объектов. Вы можете переопределить этот метод, чтобы изменить работу админки после создания объекта.

ModelAdmin.response_change(request, obj)

Создает HttpResponse для change_view().

response_change вызывается после отправки формы, сохранения объекта и всех связанных объектов. Вы можете переопределить это метод, чтобы добавить дополнительную логику, выполняемую после изменения объекта.

ModelAdmin.response_delete(request, obj_display, obj_id)

Создает HttpResponse для delete_view().

response_delete вызывается после удаления объекта. Вы можете переопределить это метод, чтобы добавить дополнительную логику, выполняемую после удаления объекта.

obj_display - строка с названием удаленного объекта.

obj_id – сериализированный идентификатор, который использовался для получения удаленного объекта.

ModelAdmin.get_changeform_initial_data(request)

Позволяет добавить начальные данные для формы изменения объекта. По умолчанию используются параметры из GET. Например, ?name=initial_value для поля name установит начальное значение в initial_value.

Этот метод должен вернуть словарь вида {'fieldname': 'fieldval'}:

def get_changeform_initial_data(self, request):
    return {'name': 'custom_initial_value'}
ModelAdmin.get_deleted_objects(objs, request)

A hook for customizing the deletion process of the delete_view() and the «delete selected» action.

The objs argument is a homogeneous iterable of objects (a QuerySet or a list of model instances) to be deleted, and request is the HttpRequest.

This method must return a 4-tuple of (deleted_objects, model_count, perms_needed, protected).

deleted_objects is a list of strings representing all the objects that will be deleted. If there are any related objects to be deleted, the list is nested and includes those related objects. The list is formatted in the template using the unordered_list filter.

model_count is a dictionary mapping each model’s verbose_name_plural to the number of objects that will be deleted.

perms_needed is a set of verbose_names of the models that the user doesn’t have permission to delete.

protected is a list of strings representing of all the protected related objects that can’t be deleted. The list is displayed in the template.

Остальные методы

ModelAdmin.add_view(request, form_url='', extra_context=None)

Представление Django для страницы добавления объекта модели. Смотрите описание ниже.

ModelAdmin.change_view(request, object_id, form_url='', extra_context=None)

Django view for the model instance editing page. See note below.

ModelAdmin.changelist_view(request, extra_context=None)

Представление Django для страницы отображения всех объектов модели. Смотрите описание ниже.

ModelAdmin.delete_view(request, object_id, extra_context=None)

Представление Django для страницы подтверждения удаления объектов. Смотрите описание ниже.

ModelAdmin.history_view(request, object_id, extra_context=None)

Представление Django для страницы истории изменений объекта модели.

В отличии от методов ModelAdmin описанных выше, которые позволяют изменять поведение интерфейса администратора, эти пять методов используются как представления Django для выполнения CRUD-операций над объектами модели. В результате, полностью переопределив эти методы можно радикально изменить интерфейс администратора.

Одна из причин переопределить эти методы – добавить данные в контекст шаблона. В этом примере представление для изменения объекта добавляет дополнительные данные в контекст, чтобы отобразить их в шаблоне:

class MyModelAdmin(admin.ModelAdmin):

    # A template for a very customized change view:
    change_form_template = 'admin/myapp/extras/openstreetmap_change_form.html'

    def get_osm_info(self):
        # ...
        pass

    def change_view(self, request, object_id, form_url='', extra_context=None):
        extra_context = extra_context or {}
        extra_context['osm_data'] = self.get_osm_info()
        return super().change_view(
            request, object_id, form_url, extra_context=extra_context,
        )

Эти представления возвращают объект TemplateResponse, что позволяет легко изменить данные ответа перед выполнением шаблона. Подробности смотрите в разделе о TemplateResponse.

Добавление статических файлов в ModelAdmin

В некоторых ситуациях вам может понадобиться добавить CSS и/или JavaScript файлы в представления добавления или изменения объектов. Вы можете выполнить это добавив класс Media в ModelAdmin:

class ArticleAdmin(admin.ModelAdmin):
    class Media:
        css = {
            "all": ("my_styles.css",)
        }
        js = ("my_code.js",)

Приложение staticfiles добавляет STATIC_URL (или MEDIA_URL если STATIC_URL равно None) к указанным путям. Это же правильно применяется и к определению статических файлов для форм.

jQuery

Javascript интерфейса администратора использует библиотеку jQuery.

To avoid conflicts with user-supplied scripts or libraries, Django’s jQuery (version 3.4.1) is namespaced as django.jQuery. If you want to use jQuery in your own admin JavaScript without including a second copy, you can use the django.jQuery object on changelist and add/edit views.

Changed in Django 3.0:

jQuery was upgraded from 3.3.1 to 3.4.1.

Класс ModelAdmin использует jQuery по умолчанию, так что вам не нужно добавлять jQuery в список media-файлов ModelAdmin. Если вам необходима библиотека jQuery в глобальном пространстве имен, например при использовании плагинов jQuery, или более новая версия jQuery, вам необходимо добавить собственную копию jQuery.

Django содержит сжатую и „minified“ версию jQuery, как jquery.js и jquery.min.js соответственно.

ModelAdmin и InlineModelAdmin содержат свойство media, которое возвращает список объектов Media, которые содержат путь к JavaScript файлам для форм и наборов форм. Если DEBUG равна True, будет использована несжатая версия jquery.js, иначе сжатая версия.

Дополнительная проверка данных в интерфейсе администратора

You can also add custom validation of data in the admin. The automatic admin interface reuses django.forms, and the ModelAdmin class gives you the ability define your own form:

class ArticleAdmin(admin.ModelAdmin):
    form = MyArticleAdminForm

Вы можете определить форму MyArticleAdminForm где угодно, просто импортируйте ее. В собственной форме вы можете добавить дополнительную проверку данных для любого поля:

class MyArticleAdminForm(forms.ModelForm):
    def clean_name(self):
        # do something that validates your data
        return self.cleaned_data["name"]

Важно использовать ModelForm, чтобы избежать проблем и ошибок. Подробности смотрите в документации о формах раздел про проверку полей и, особенно, раздел о переопределении метода clean() в ModelForm.

Объект InlineModelAdmin

class InlineModelAdmin
class TabularInline
class StackedInline

Интерфейс администратора позволяет редактировать связанные объекты на одной странице с родительским объектом. Это называется «inlines». Например, у нас есть две модели:

from django.db import models

class Author(models.Model):
   name = models.CharField(max_length=100)

class Book(models.Model):
   author = models.ForeignKey(Author, on_delete=models.CASCADE)
   title = models.CharField(max_length=100)

Вы можете редактировать книги автора на странице редактирования автора. Вы добавляете «inlines» к модели добавив их в ModelAdmin.inlines:

from django.contrib import admin

class BookInline(admin.TabularInline):
    model = Book

class AuthorAdmin(admin.ModelAdmin):
    inlines = [
        BookInline,
    ]

Django предоставляет два подкласса InlineModelAdmin:

Разница между ними только в используемом шаблоне.

Параметры InlineModelAdmin

InlineModelAdmin содержит некоторые возможности ModelAdmin и собственные. Общие методы и атрибуты определены в классе BaseModelAdmin, вот они:

The InlineModelAdmin class adds or customizes:

InlineModelAdmin.model

Модель используемая в «inline». Обязательный параметр.

InlineModelAdmin.fk_name

Название внешнего ключа модели. В большинстве случаев он определяется автоматически, но вы должны указать fk_name, если модель содержит несколько внешних ключей к родительской модели.

InlineModelAdmin.formset

По умолчанию – BaseInlineFormSet. Использование собственного класса предоставляет большие возможности для переопределения поведения по умолчанию. Смотрите раздел о наборах модельных форм.

InlineModelAdmin.form

Значение form по умолчанию – ModelForm. Это значение передается в inlineformset_factory() при создании набора форм.

Предупреждение

При добавлении собственной валидации в форму InlineModelAdmin, учитывайте состояние родительской модели. Если родительская форма не пройдет валидацию, она может содержать не консистентные данные. Смотрите предупреждение в Валидация в ModelForm.

InlineModelAdmin.classes

A list or tuple containing extra CSS classes to apply to the fieldset that is rendered for the inlines. Defaults to None. As with classes configured in fieldsets, inlines with a collapse class will be initially collapsed and their header will have a small «show» link.

InlineModelAdmin.extra

Указывает количество пустых форм для добавления объектов в наборе форм. Подробности смотрите в разделе о наборе форм.

Если JavaScript включен в браузере, ссылка «Add another» позволит добавить новую пустую форму в дополнение к формам указанным параметром extra.

Ссылка не появится если количество отображаемых форм превышает значение в параметре max_num, или если у пользователя отключен JavaScript.

InlineModelAdmin.get_extra() позволяет указать количество дополнительных форм.

InlineModelAdmin.max_num

Указывает максимальное количество форм. Этот параметр не определяет количество связанных объектов. Подробности смотрите в разделе Ограничение количества редактируемых объектов.

InlineModelAdmin.get_max_num() позволяет указать максимальное количество дополнительных форм.

InlineModelAdmin.min_num

Указывает минимальное количество отображаемых форм. Смотрите modelformset_factory().

InlineModelAdmin.get_min_num() позволяет указать минимальное количество отображаемых форм.

InlineModelAdmin.raw_id_fields

По умолчанию Django использует <select> для полей ForeignKey. Если связанных объектов очень много, создание <select> может быть очень затратным процессом.

raw_id_fields содержит список полей, которые будут использовать поле Input для ForeignKey или ManyToManyField:

class BookInline(admin.TabularInline):
    model = Book
    raw_id_fields = ("pages",)
InlineModelAdmin.template

Шаблон для отображения.

InlineModelAdmin.verbose_name

Позволяет переопределить значение verbose_name класса Meta модели.

InlineModelAdmin.verbose_name_plural

Позволяет переопределить значение verbose_name_plural класса Meta модели.

InlineModelAdmin.can_delete

Определяет можно ли удалять связанные объекты. По умолчанию равно True.

Определяет показывать ли ссылку на форму изменения для связанных объектов, которые можно изменять. По умолчанию равно False.

InlineModelAdmin.get_formset(request, obj=None, **kwargs)

Returns a BaseInlineFormSet class for use in admin add/change views. obj is the parent object being edited or None when adding a new parent. See the example for ModelAdmin.get_formsets_with_inlines.

InlineModelAdmin.get_extra(request, obj=None, **kwargs)

Возвращает количество форм. По умолчанию возвращает значение атрибута InlineModelAdmin.extra.

Вы можете переопределить метод и добавить логику для определения количества форм. Например, учитывать данные объекта модели(передается как именованный аргумент obj):

class BinaryTreeAdmin(admin.TabularInline):
    model = BinaryTree

    def get_extra(self, request, obj=None, **kwargs):
        extra = 2
        if obj:
            return extra - obj.binarytree_set.count()
        return extra
InlineModelAdmin.get_max_num(request, obj=None, **kwargs)

Возвращает максимальное количество дополнительных форм. По умолчанию возвращает значение атрибута InlineModelAdmin.max_num.

Вы можете переопределить метод и добавить логику для определения максимального количества форм. Например, учитывать данные объекта модели(передается как именованный аргумент obj):

class BinaryTreeAdmin(admin.TabularInline):
    model = BinaryTree

    def get_max_num(self, request, obj=None, **kwargs):
        max_num = 10
        if obj and obj.parent:
            return max_num - 5
        return max_num
InlineModelAdmin.get_min_num(request, obj=None, **kwargs)

Возвращает минимальное количество дополнительных форм. По умолчанию возвращает значение атрибута InlineModelAdmin.min_num.

Вы можете переопределить метод и добавить логику для определения минимального количества форм. Например, учитывать данные объекта модели(передается как именованный аргумент obj).

InlineModelAdmin.has_add_permission(request, obj)

Should return True if adding an inline object is permitted, False otherwise. obj is the parent object being edited or None when adding a new parent.

InlineModelAdmin.has_change_permission(request, obj=None)

Should return True if editing an inline object is permitted, False otherwise. obj is the parent object being edited.

InlineModelAdmin.has_delete_permission(request, obj=None)

Should return True if deleting an inline object is permitted, False otherwise. obj is the parent object being edited.

Примечание

The obj argument passed to InlineModelAdmin methods is the parent object being edited or None when adding a new parent.

Работа с моделью с несколькими внешними ключами к одной модели

Модель может содержать несколько внешних ключей к одной модели, например:

from django.db import models

class Friendship(models.Model):
    to_person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name="friends")
    from_person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name="from_friends")

Если вы хотите использовать «inline» для этой модели на странице редактирования/добавления объектов Person, вам необходимо указать какой внешний ключ использовать:

from django.contrib import admin
from myapp.models import Friendship

class FriendshipInline(admin.TabularInline):
    model = Friendship
    fk_name = "to_person"

class PersonAdmin(admin.ModelAdmin):
    inlines = [
        FriendshipInline,
    ]

Работа со связями многие-ко-многим

По умолчанию, для полей ManyToManyField используется виджет определенный интерфейсом администратора. В зависимости от параметров ModelAdmin``может использоваться стандартное HTML поле ``<select multiple>, горизонтальный или вертикальный фильтр, или виджет raw_id_admin. Однако вместо этого можно использовать «inline».

Предположим у нас есть следующие модели:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, related_name='groups')

Необходимо определить объект InlineModelAdmin для связи многое-ко-многим:

from django.contrib import admin

class MembershipInline(admin.TabularInline):
    model = Group.members.through

class PersonAdmin(admin.ModelAdmin):
    inlines = [
        MembershipInline,
    ]

class GroupAdmin(admin.ModelAdmin):
    inlines = [
        MembershipInline,
    ]
    exclude = ('members',)

Есть две вещи в этом примере, которые следует отметить.

Первая - класс MembershipInline ссылается на Group.members.through. Атрибут through указывает на модель управляющую связью многое-ко-многим. Эта модель автоматически создается Django при определении связи.

Вторая – класс GroupAdmin должен явно исключить поле members. Django отображает поле для связи многое-ко-многим (в нашем случае с моделью Group). Если вы хотите использовать «inline», необходимо указать Django, что поле не нужно отображать - иначе мы получим два виджета для редактирования связи.

Обратите внимание, при использовании такого подхода сигнал m2m_changed не вызывается. Это вызвано тем, что для админки through просто модель с двумя внешними ключами, а не связь много-ко-многим.

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

Работа с промежуточной моделью связи многое-ко-многим

Если указать аргумент through для поля ManyToManyField, интерфейс администратора не отобразит поле для редактирования. Это связано с тем, что промежуточная модель требует больше данных, чем позволяет ввести стандартное поле.

However, we still want to be able to edit that information inline. Fortunately, we can do this with inline admin models. Suppose we have the following models:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

class Membership(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

Для начала определим отображение модели Membership в интерфейсе администратора:

class MembershipInline(admin.TabularInline):
    model = Membership
    extra = 1

This example uses the default InlineModelAdmin values for the Membership model, and limits the extra add forms to one. This could be customized using any of the options available to InlineModelAdmin classes.

Теперь определим отображение моделей Person и Group:

class PersonAdmin(admin.ModelAdmin):
    inlines = (MembershipInline,)

class GroupAdmin(admin.ModelAdmin):
    inlines = (MembershipInline,)

Теперь зарегистрируем модели Person и Group в интерфейсе администратора:

admin.site.register(Person, PersonAdmin)
admin.site.register(Group, GroupAdmin)

Теперь вы можете редактировать объекты Membership на странице объектов Person и Group.

Использование связей с несколькими моделями в интерфейсе администратора

Вы можете использовать «inline» для связей с несколькими моделями(generic relations). Предположим, у вас есть следующие модели:

from django.contrib.contenttypes.fields import GenericForeignKey
from django.db import models

class Image(models.Model):
    image = models.ImageField(upload_to="images")
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey("content_type", "object_id")

class Product(models.Model):
    name = models.CharField(max_length=100)

Если вы хотите редактировать и добавлять объекты Image на странице добавления/редактирования объектов Product, вы можете использовать GenericTabularInline или GenericStackedInline (подклассы GenericInlineModelAdmin) из модуля admin. Они отображают группы форм для добавления и редактирования связанных объектов, как и аналогичные классы из приложения интерфейса администратора. Пример admin.py для наших моделей:

from django.contrib import admin
from django.contrib.contenttypes.admin import GenericTabularInline

from myproject.myapp.models import Image, Product

class ImageInline(GenericTabularInline):
    model = Image

class ProductAdmin(admin.ModelAdmin):
    inlines = [
        ImageInline,
    ]

admin.site.register(Product, ProductAdmin)

Подробности смотрите в разделе о contenttypes.

Переопределение шаблонов в интерфейсе администратора

You can override many of the templates which the admin module uses to generate the various pages of an admin site. You can even override a few of these templates for a specific app, or a specific model.

Настройка каталогов в шаблонами

Шаблоны интерфейса администратора находятся в каталоге contrib/admin/templates/admin.

Чтобы переопределить шаблоны, для начала создайте каталог admin в каталоге templates проекта. Это может быть любой каталог, указанный в опции DIRS бэкенда DjangoTemplates` в настройке TEMPLATES. Если вы изменили опцию 'loaders', убедитесь, что 'django.template.loaders.filesystem.Loader' стоит перед 'django.template.loaders.app_directories.Loader'. Таким образом ваши шаблоны будет найдены до того, как Django найдет шаблоны из django.contrib.admin.

В каталоге admin создайте подкаталоги с названием приложений. В этих подкаталогах создайте подкаталоги для моделей. Заметим, что интерфейс администратора преобразует название модели в нижний регистр, так что убедитесь что название каталогов в нижнем регистре, если вы использует файловую систему учитывающую регистр названий каталог.

Чтобы переопределить шаблон для определенного приложения, скопируйте и отредактируйте необходимый шаблон из каталога django/contrib/admin/templates/admin и сохраните его в созданном подкаталоге.

Например, если необходимо изменить шаблон для представления списка объектов для всех моделей в приложении my_app, скопируйте contrib/admin/templates/admin/change_list.html в каталог templates/admin/my_app/ проекта и выполните необходимые изменения.

Если необходимо изменить шаблон только для модели „Page“, скопируйте тот же файл в каталог templates/admin/my_app/page проекта.

Переопределение или замена шаблона в интерфейсе администратора

Учитывая модульную структуру шаблонов в интерфейсе администратора, как правило нет необходимости заменять весь шаблон. Целесообразней переопределить только необходимый блок шаблона.

Продолжим пример выше. Например, необходимо добавить ссылку после ссылки History для модели Page. Изучив change_form.html можно увидеть, что нам необходимо переопределить только блок object-tools-items. Вот наш новый шаблон change_form.html :

{% extends "admin/change_form.html" %}
{% load i18n admin_urls %}
{% block object-tools-items %}
    <li>
        <a href="{% url opts|admin_urlname:'history' original.pk|admin_urlquote %}" class="historylink">{% trans "History" %}</a>
    </li>
    <li>
        <a href="mylink/" class="historylink">My Link</a>
    </li>
    {% if has_absolute_url %}
        <li>
            <a href="{% url 'admin:view_on_site' content_type_id original.pk %}" class="viewsitelink">{% trans "View on site" %}</a>
        </li>
    {% endif %}
{% endblock %}

Вот и все! Добавим шаблон в каталог templates/admin/my_app и ссылка появится на странице редактирования объекта для всех моделей приложения my_app.

Шаблоны, которые можно переопределить для приложения или модели

Не каждый шаблон в contrib/admin/templates/admin можно переопределить для приложения или модели. Вот список переопределяемых шаблонов:

  • actions.html
  • app_index.html
  • change_form.html
  • change_form_object_tools.html
  • change_list.html
  • change_list_object_tools.html
  • change_list_results.html
  • date_hierarchy.html
  • delete_confirmation.html
  • object_history.html
  • pagination.html
  • popup_response.html
  • prepopulated_fields_js.html
  • search_form.html
  • submit_line.html

For those templates that cannot be overridden in this way, you may still override them for your entire project by placing the new version in your templates/admin directory. This is particularly useful to create custom 404 and 500 pages.

Примечание

Некоторые шаблоны, такие как change_list_request.html используются для отображения включаемых тегов(inclusion tags). Вы можете переопределить их, но лучше создать собственную версию тега, которая будет использовать новый шаблон. В этом случае вы сможете использовать оба шаблона.

Главный шаблон и шаблон страницы входа

Чтобы переопределить шаблоны главной страницы и страниц входа/выхода, лучше создать собственный экземпляр AdminSite (смотрите ниже), и изменить свойства AdminSite.index_template , AdminSite.login_template и AdminSite.logout_template.

Объект AdminSite

class AdminSite(name='admin')

Интерфейс администратора Django представлен экземпляром django.contrib.admin.sites.AdminSite. По умолчанию, экземпляр этого класса находится в django.contrib.admin.site и вы можете зарегистрировать модели с подклассами ModelAdmin в нем.

If you want to customize the default admin site, you can override it.

При создании экземпляра AdminSite, вы можете указать уникальное название экземпляра приложения передав аргумент name в конструктор. Это название используется для идентификации экземпляра что важно при поиске URL-ов интерфейса администратора. Если этот аргумент не указан, будет использовано значение по умолчанию admin. Смотрите раздел Настройка класса AdminSite о том, как настраивать класс AdminSite.

Атрибуты AdminSite

Можно переопределить или заменить основные шаблоны в интерфейсе администратора как это описано в разделе Переопределение шаблонов в интерфейсе администратора.

AdminSite.site_header

Текст, который отображается в заголовке каждой страницы, в <h1>. По умолчанию «Django administration».

AdminSite.site_title

Текст, который добавляется в <title> каждой страницы. По умолчанию «Django site admin».

AdminSite.site_url

URL для ссылки «View site» на верху каждой страницы админки. По умолчанию site_url равен /. Чтобы убрать эту ссылку, укажите None.

For sites running on a subpath, the each_context() method checks if the current request has request.META['SCRIPT_NAME'] set and uses that value if site_url isn’t set to something other than /.

AdminSite.index_title

Текст, который отображается в верху главной странице админки. По умолчанию «Site administration».

AdminSite.index_template

Шаблон, который будет использоваться для главной страницы.

AdminSite.app_index_template

Шаблон, который будет использоваться для главной страницей приложения.

AdminSite.empty_value_display

Строка, которая используется при отображении пустых значений на странице списка объектов. По умолчанию равна "-". Значение можно переопределить для ModelAdmin и для каждого поля ModelAdmin, указав атрибут empty_value_display для поля. Примеры смотрите в ModelAdmin.empty_value_display.

AdminSite.login_template

Шаблон, который будет использоваться для страницы входа.

AdminSite.login_form

Подкласс AuthenticationForm который будет использовать для представления авторизации в интерфейсе администратора.

AdminSite.logout_template

Шаблон, который будет использоваться для страницы выхода.

AdminSite.password_change_template

Шаблон, который будет использоваться для страницы смены пароля.

AdminSite.password_change_done_template

Шаблон, который будет использоваться для страницы завершения смены пароля.

Методы AdminSite

AdminSite.each_context(request)

Возвращает словарь переменных, которые будут добавлены в контекст шаблона для каждой странице этой админки.

По умолчанию содержит следующие переменны:

  • site_header: AdminSite.site_header

  • site_title: AdminSite.site_title

  • site_url: AdminSite.site_url

  • has_permission: AdminSite.has_permission()

  • available_apps: список приложений из регистра приложений, которые доступны для текущего пользователя. Каждый элемент списка содержит словарь, который представляет приложение, со следующими ключами:

    • app_label: название приложения
    • app_url: URL главное страницы приложения в админке
    • has_module_perms: булево, которые указывает есть ли у пользователя права к главной странице приложения в админке
    • models: список моделей прилоджения

    Каждая модель представлена словарем со следующими ключами:

    • object_name: название класса модели
    • name: множественное название модели
    • perms: a dict tracking add, change, delete, and view permissions
    • admin_url: URL к странице списка объектов модели в админке
    • add_url: URL к странице добавления объекта модели в админке
AdminSite.has_permission(request)

Возвращает True, если пользователь из переданного HttpRequest имеет доступ хотя бы к одной странице админки. По умолчанию проверяется равны ли User.is_active и User.is_staff True.

AdminSite.register(model_or_iterable, admin_class=None, **options)

Registers the given model class (or iterable of classes) with the given admin_class. admin_class defaults to ModelAdmin (the default admin options). If keyword arguments are given – e.g. list_display – they’ll be applied as options to the admin class.

Raises ImproperlyConfigured if a model is abstract. and django.contrib.admin.sites.AlreadyRegistered if a model is already registered.

Добавление экземпляра AdminSite в URLconf

The last step in setting up the Django admin is to hook your AdminSite instance into your URLconf. Do this by pointing a given URL at the AdminSite.urls method. It is not necessary to use include().

В этом примере мы добавляем экземпляр по умолчанию AdminSite, который находится в django.contrib.admin.site, для URL /admin/

# urls.py
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

Настройка класса AdminSite

If you’d like to set up your own admin site with custom behavior, you’re free to subclass AdminSite and override or add anything you like. Then, create an instance of your AdminSite subclass (the same way you’d instantiate any other Python class) and register your models and ModelAdmin subclasses with it instead of with the default site. Finally, update myproject/urls.py to reference your AdminSite subclass.

myapp/admin.py
from django.contrib.admin import AdminSite

from .models import MyModel

class MyAdminSite(AdminSite):
    site_header = 'Monty Python administration'

admin_site = MyAdminSite(name='myadmin')
admin_site.register(MyModel)
myproject/urls.py
from django.urls import path

from myapp.admin import admin_site

urlpatterns = [
    path('myadmin/', admin_site.urls),
]

Обратите внимание, при использовании своего экземпляра AdminSite, возможно, вы не захотите отключить автоматический поиск модулей admin и регистрацию их в стандартной админке. Для этого укажите 'django.contrib.admin.apps.SimpleAdminConfig' вместо 'django.contrib.admin' в настройке INSTALLED_APPS. Скорее всего в этом случае вы будете импортировать модули admin в вашем модуле myproject.admin.

Overriding the default admin site

You can override the default django.contrib.admin.site by setting the default_site attribute of a custom AppConfig to the dotted import path of either a AdminSite subclass or a callable that returns a site instance.

myproject/admin.py
from django.contrib import admin

class MyAdminSite(admin.AdminSite):
    ...
myproject/apps.py
from django.contrib.admin.apps import AdminConfig

class MyAdminConfig(AdminConfig):
    default_site = 'myproject.admin.MyAdminSite'
myproject/settings.py
INSTALLED_APPS = [
    ...
    'myproject.apps.MyAdminConfig',  # replaces 'django.contrib.admin'
    ...
]

Несколько интерфейсов администратора в одном URLconf

You can create multiple instances of the admin site on the same Django-powered website. Create multiple instances of AdminSite and place each one at a different URL.

В этом примере, URL-ы /basic-admin/ и /advanced-admin/ ведут к различным экземплярам AdminSitemyproject.admin.basic_site и myproject.admin.advanced_site соответственно:

# urls.py
from django.urls import path
from myproject.admin import advanced_site, basic_site

urlpatterns = [
    path('basic-admin/', basic_site.urls),
    path('advanced-admin/', advanced_site.urls),
]

Конструктор AdminSite принимает единственный аргумент – название экземпляра, которое может быть любым. Это значение будет использоваться как префикс для названий URL при их поиске. Это необходимо если вы используете несколько экземпляров AdminSite.

Добавление представлений в интерфейс администратора

Как и ModelAdmin AdminSite содержит метод get_urls(), который можно переопределить и добавить собственные представления в интерфейс администратора. Переопределите метод get_urls() и добавьте URL-шаблоны с вашими представлениями.

Примечание

Каждое представление, которое использует шаблоны интерфейса администратора или унаследованные шаблоны, должно указать request.current_app перед рендерингом шаблона. Он должен быть равен self.name, если представление определенно в AdminSite, или self.admin_site.name, если определено в ModelAdmin.

Adding a password reset feature

You can add a password reset feature to the admin site by adding a few lines to your URLconf. Specifically, add these four patterns:

from django.contrib.auth import views as auth_views

path(
    'admin/password_reset/',
    auth_views.PasswordResetView.as_view(),
    name='admin_password_reset',
),
path(
    'admin/password_reset/done/',
    auth_views.PasswordResetDoneView.as_view(),
    name='password_reset_done',
),
path(
    'reset/<uidb64>/<token>/',
    auth_views.PasswordResetConfirmView.as_view(),
    name='password_reset_confirm',
),
path(
    'reset/done/',
    auth_views.PasswordResetCompleteView.as_view(),
    name='password_reset_complete',
),

(Предполагается что вы уже добавили приложения интерфейса администратора к admin/ и что оно указано после всех URL-шаблонов начинающихся с ^admin/ ).

Наличие URL-шаблона с названием admin_password_reset приведет к появлению ссылки «забыли ваш пароль?» на странице входа в интерфейсе администратора.

Объекты LogEntry

class models.LogEntry

Класс LogEntry следит за добавлением, изменение и удалением объектов, которые выполняются через админку.

Атрибуты LogEntry

LogEntry.action_time

Дата и время действия.

LogEntry.user

Пользователь (объект AUTH_USER_MODEL), который выполнил действие.

LogEntry.content_type

ContentType измененного объекта.

LogEntry.object_id

Текстовое представление первичного ключа измененного объекта.

LogEntry.object_repr

Результат repr() над объектом после изменения.

LogEntry.action_flag

Тип действия: ADDITION, CHANGE, DELETION.

Например, чтобы получить все добавления через админку:

from django.contrib.admin.models import ADDITION, LogEntry

LogEntry.objects.filter(action_flag=ADDITION)
LogEntry.change_message

The detailed description of the modification. In the case of an edit, for example, the message contains a list of the edited fields. The Django admin site formats this content as a JSON structure, so that get_change_message() can recompose a message translated in the current user language. Custom code might set this as a plain string though. You are advised to use the get_change_message() method to retrieve this value instead of accessing it directly.

Методы LogEntry

LogEntry.get_edited_object()

Возвращает связанный объект.

LogEntry.get_change_message()

Formats and translates change_message into the current user language. Messages created before Django 1.10 will always be displayed in the language in which they were logged.

Поиск URL-ов интерфейса администратора

После установки AdminSite можно указывать ссылки к представлениям интерфейса администратора используя систему поиска URL-ов.

AdminSite предоставляет следующие именованные URL-шаблоны:

Страница Название URL-а Параметры
Главная index  
Login login  
Выхода logout  
Смена пароля password_change  
Завершения смены пароля password_change_done  
i18n JavaScript jsi18n  
Главная страница приложения app_list app_label
Редирект на страницу объекта view_on_site content_type_id, object_id

Каждый экземпляр ModelAdmin предоставляет дополнительные именованные URL-шаблоны:

Страница Название URL-а Параметры
Список объектов {{ app_label }}_{{ model_name }}_changelist  
Добавления объекта {{ app_label }}_{{ model_name }}_add  
Истории {{ app_label }}_{{ model_name }}_history object_id
Удаления объекта {{ app_label }}_{{ model_name }}_delete object_id
Изменения объекта {{ app_label }}_{{ model_name }}_change object_id

UserAdmin предоставляет следующие именованные URL-шаблоны:

Страница Название URL-а Параметры
Смена пароля auth_user_password_change user_id

Эти именованные URL-шаблоны зарегистрированы с названием экземпляра приложения admin и названием экземпляра приложения, указанным при создании AdminSite.

Например, нам необходимо получить ссылку на страницу изменения объекта модели Choice (из приложения polls) в стандартном интерфейсе администратора. Для этого необходимо выполнить следующий код:

>>> from django.urls import reverse
>>> c = Choice.objects.get(...)
>>> change_url = reverse('admin:polls_choice_change', args=(c.id,))

Этот код найдет первый зарегистрированный экземпляр приложения admin (не зависимо от определенного названия экземпляра) и найдет ссылку на представление для редактирования объекта poll.Choice.

Если необходимо найти URL в определенном экземпляре приложения, укажите значение current_app. Например, если необходимо получить ссылку на представление в экземпляре приложения с названием custom, выполните следующий код:

>>> change_url = reverse('admin:polls_choice_change', args=(c.id,), current_app='custom')

Подробности смотрите в разделе о пространстве имен в конфигурации URL-ов.

Для более удобного поиска URL-ов в шаблонах, Django предоставляет фильтр admin_urlname, который принимает название действия в качестве аргумента:

{% load admin_urls %}
<a href="{% url opts|admin_urlname:'add' %}">Add user</a>
<a href="{% url opts|admin_urlname:'delete' user.pk %}">Delete this user</a>

Название действия совпадает с последней частью названия URL-шаблона в ModelAdmin, которые описаны выше. Значение opts может быть любым объектом содержащим app_label и model_name, эта переменная обычно указывается представлением в интерфейсе администратора для текущей модели.

Декоратор staff_member_required

staff_member_required(redirect_field_name='next', login_url='admin:login')

Декоратор используется для представлений админки, чтобы проверять авторизацию. Представления с этим декоратором будут работать следующим образом:

  • Если пользователь авторизирован, и он администратор (User.is_staff=True), и активен (User.is_active=True), выполнить представление.
  • Иначе запросе будет перенаправлен на URL, указанный в параметре login_url, который по умолчанию равен значению аргумента с названием из redirect_field_name. Например: /admin/login/?next=/admin/polls/question/3/.

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

from django.contrib.admin.views.decorators import staff_member_required

@staff_member_required
def my_view(request):
    ...