Spec-Zone.ru › Django 3.2

Сайт администрирования Django

Одна из самых мощных частей Django — это автоматический интерфейс администрирования. Он считывает метаданные из ваших моделей, чтобы предоставить быстрый, ориентированный на модели интерфейс, где авторизованные пользователи могут управлять контентом на вашем сайте. Рекомендуется использовать админку только в качестве внутреннего инструмента организации. Она не предназначена для построения всего вашего фронтенда вокруг неё.

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

В этом документе мы обсудим, как активировать, использовать и настроить интерфейс администрирования Django.

Обзор

Админка включена в шаблон проекта по умолчанию, используемый startproject.

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

  1. Добавьте 'django.contrib.admin' и его зависимости — django.contrib.auth, django.contrib.contenttypes, django.contrib.messages и django.contrib.sessions — в ваше значение INSTALLED_APPS.
  2. Настройте бэкенд DjangoTemplates в настройке TEMPLATES с django.template.context_processors.request, django.contrib.auth.context_processors.auth, и django.contrib.messages.context_processors.messages в опции 'context_processors' OPTIONS.

    Изменено в Django 3.1:

    django.template.context_processors.request было добавлено как требование в опцию 'context_processors' для поддержки новой функции AdminSite.enable_nav_sidebar.

  3. Если вы настраивали значение MIDDLEWARE, django.contrib.auth.middleware.AuthenticationMiddleware и django.contrib.messages.middleware.MessageMiddleware должны быть включены.
  4. Подключите URL-адреса админки к вашему URLconf.

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

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

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

Другие темы

  • Действия админки
  • Генератор документации Django admin
  • Настройка JavaScript в админке

См. также

Для получения информации о предоставлении статических файлов (изображения, JavaScript и CSS), связанных с админкой в продакшене, см. Предоставление файлов.

Есть проблемы? Попробуйте Вопросы и ответы: админка.

ModelAdmin объекты

class ModelAdmin

Класс ModelAdmin представляет модель в интерфейсе администрирования. Обычно они хранятся в файле с именем admin.py в вашем приложении. Давайте рассмотрим пример 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)

Декоратор register

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

Также есть декоратор для регистрации ваших классов ModelAdmin:

from django.contrib import admin
from .models import Author

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

Он принимает один или несколько классов моделей для регистрации в ModelAdmin. Если вы используете пользовательский AdminSite, передайте его с помощью ключевого аргумента site:

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

Вы не можете использовать этот декоратор, если вам нужно сослаться на ваш класс администратора модели в методе __init__() , например, super(PersonAdmin, self).__init__(*args, **kwargs). Вы можете использовать super().__init__(*args, **kwargs).

Обнаружение файлов администрирования

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

class apps.AdminConfig

Это класс AppConfig по умолчанию для админки. Он вызывает autodiscover() при запуске Django.

class apps.SimpleAdminConfig

Этот класс работает как AdminConfig, за исключением того, что он не вызывает autodiscover().

default_site

Путь импорта до класса сайта администрирования по умолчанию или вызываемый объект, возвращающий экземпляр сайта. По умолчанию 'django.contrib.admin.sites.AdminSite'. См. Замена сайта администрирования по умолчанию для использования.

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'

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

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')

    @admin.display(empty_value='???')
    def view_birth_date(self, obj):
        return obj.birth_date
Изменено в Django 3.2:

Аргумент empty_value для декоратора display() эквивалентен установке атрибута 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',)

Поскольку модель Author имеет только три поля, 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.

Опция fields принимает те же типы значений, что и list_display, за исключением того, что вызываемые функции не принимаются. Имена методов модели и модели администрирования будут использоваться только в том случае, если они указаны в readonly_fields.

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

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

Примечание

Эта опция fields не следует путать с ключом словаря fields, который находится внутри опции fieldsets, как описано в следующем разделе.

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

ModelAdmin.fieldsets

Установите fieldsets для управления макетом страниц администрирования «Добавить» и «Изменить».

fieldsets — это список пар кортежей, где каждая пара кортежей представляет собой <fieldset> на странице формы администрирования. (Поле <fieldset> — это «раздел» формы.)

Парные кортежи имеют формат (name, field_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

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

Словарь 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 может содержать значения, определённые в readonly_fields для отображения в режиме только для чтения.

    Если вы добавляете имя вызываемой функции в fields, то применяется то же правило, что и с опцией fields: вызываемая функция должна быть указана в readonly_fields.

  • classes

    Список или кортеж дополнительных CSS-классов, которые нужно применить к набору полей.

    Пример:

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

    Две полезные класса, определенные стилем CSS по умолчанию для админ-сайта, — это collapse и wide. Наборы полей со стилем collapse будут изначально свернуты в администрировании и заменены небольшой ссылкой «развернуть». Наборы полей со стилем wide будут иметь дополнительное горизонтальное пространство.

  • description

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

    Обратите внимание, что это значение не экранируется с помощью HTML при отображении в интерфейсе администрирования. Это позволяет включать HTML, если это необходимо. В качестве альтернативы можно использовать обычный текст и django.utils.html.escape(), чтобы экранировать любые специальные символы HTML.

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 форм.

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

Если вы хотите использовать пользовательский виджет с полем связи (т. е. ForeignKey или ManyToManyField), убедитесь, что вы не включили имя этого поля в raw_id_fields, radio_fields, или autocomplete_fields.

formfield_overrides не позволит вам изменить виджет для полей связи, у которых установлены raw_id_fields, radio_fields, или autocomplete_fields. Это потому, что raw_id_fields, radio_fields, и autocomplete_fields подразумевают собственные пользовательские виджеты.

ModelAdmin.inlines

См. InlineModelAdmin объекты ниже, а также ModelAdmin.get_formsets_with_inlines().

ModelAdmin.list_display

Установите list_display для управления отображением полей на странице изменения списка в админ-панели.

Пример:

list_display = ('first_name', 'last_name')

Если list_display не задано, сайт администрирования отобразит один столбец, показывающий представление __str__() каждого объекта.

В list_display можно использовать четыре типа значений. Все, кроме самых простых, могут использовать декоратор display() для настройки отображения поля:

  • Имя поля модели. Например:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'last_name')
    
  • Вызываемый объект, принимающий один аргумент — экземпляр модели. Например:

    @admin.display(description='Name')
    def upper_case_name(obj):
        return ("%s %s" % (obj.first_name, obj.last_name)).upper()
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = (upper_case_name,)
    
  • Строка, представляющая метод ModelAdmin модели, принимающий один аргумент — экземпляр модели. Например:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('upper_case_name',)
    
        @admin.display(description='Name')
        def upper_case_name(self, obj):
            return ("%s %s" % (obj.first_name, obj.last_name)).upper()
    
  • Строка, представляющая атрибут или метод модели (без обязательных аргументов). Например:

    from django.contrib import admin
    from django.db import models
    
    class Person(models.Model):
        name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        @admin.display(description='Birth decade')
        def decade_born_in(self):
            return '%d’s' % (self.birthday.year // 10 * 10)
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'decade_born_in')
    

Несколько особых случаев, связанных с list_display:

  • Если поле является ForeignKey, Django отобразит __str__() связанного объекта.
  • ManyToManyField поля не поддерживаются, так как это потребовало бы выполнения отдельного SQL-запроса для каждой строки в таблице. Если вам всё же нужно это сделать, добавьте в модель пользовательский метод и добавьте имя этого метода в list_display. (Подробнее о пользовательских методах в list_display.)
  • Если поле является BooleanField, Django отобразит значок «да», «нет» или «неизвестно» вместо True, False, или None.
  • Если указанная строка является методом модели, ModelAdmin или вызываемым объектом, Django по умолчанию экранирует вывод с помощью HTML. Чтобы экранировать входные данные пользователя и разрешить собственные неэкранированные теги, используйте 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)
    
        @admin.display
        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')
    
  • Как уже продемонстрировали некоторые примеры, при использовании вызываемого объекта, метода модели или метода ModelAdmin, можно настроить заголовок столбца, обернув вызываемый объект декоратором display() и передав аргумент description.

    Изменено в Django 3.2:

    Аргумент description декоратора display() эквивалентен прямому заданию атрибута short_description функции отображения в предыдущих версиях. Прямое задание атрибута по-прежнему поддерживается для обратной совместимости.

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

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

    Также можно использовать ModelAdmin.empty_value_display:

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

    Или на уровне поля:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'birth_date_view')
    
        @admin.display(empty_value='unknown')
        def birth_date_view(self, obj):
             return obj.birth_date
    
    Изменено в Django 3.2:

    Аргумент empty_value декоратора display() эквивалентен прямому заданию атрибута empty_value_display функции отображения в предыдущих версиях. Прямое задание атрибута по-прежнему поддерживается для обратной совместимости.

  • Если заданная строка — это метод модели, ModelAdmin или вызываемый объект, возвращающий True, False, или None, Django отобразит значки «да», «нет» или «неизвестно», если вы обернёте метод декоратором display() и передадите аргумент 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()
    
        @admin.display(boolean=True)
        def born_in_fifties(self):
            return 1950 <= self.birthday.year < 1960
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'born_in_fifties')
    
    Изменено в Django 3.2:

    Аргумент boolean декоратора display() эквивалентен прямому заданию атрибута boolean функции отображения в предыдущих версиях. Прямое задание атрибута по-прежнему поддерживается для обратной совместимости.

  • Метод __str__() так же допустим в list_display как и любой другой метод модели, поэтому такое использование допустимо:

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

    Однако, если элемент list_display представляет определённое поле базы данных, можно указать это, используя декоратор display() на методе, передав аргумент ordering:

    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)
    
        @admin.display(ordering='first_name')
        def colored_first_name(self):
            return format_html(
                '<span style="color: #{};">{}</span>',
                self.color_code,
                self.first_name,
            )
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'colored_first_name')
    

    Вышеуказанное укажет Django сортировать по полю first_name при попытке сортировки по colored_first_name в админ-панели.

    Для указания сортировки по убыванию с помощью аргумента ordering можно использовать префикс «минус» для имени поля. Используя приведенный выше пример, это будет выглядеть следующим образом:

    @admin.display(ordering='-first_name')
    

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

    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')
    
        @admin.display(ordering='author__first_name')
        def author_first_name(self, obj):
            return obj.author.first_name
    

    Выражения запроса могут быть использованы с аргументом ordering:

    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)
    
        @admin.display(ordering=Concat('first_name', Value(' '), 'last_name'))
        def full_name(self):
            return self.first_name + ' ' + self.last_name
    
    Изменено в Django 3.2:

    Аргумент ordering декоратора display() эквивалентен прямому заданию атрибута admin_order_field функции отображения в предыдущих версиях. Прямое задание атрибута по-прежнему поддерживается для обратной совместимости.

  • Элементы list_display также могут быть свойствами:

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
    
        @property
        @admin.display(
            ordering='last_name',
            description='Full name of the person',
        )
        def full_name(self):
            return self.first_name + ' ' + self.last_name
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('full_name',)
    

    Обратите внимание, что @property должно быть выше @display Если вы используете старый способ — прямое задание атрибутов, связанных с отображением, вместо использования декоратора display() — имейте в виду, что функцию property() нужно использовать, а не декоратор @property:

    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)
    
  • Имена полей в list_display также будут отображаться в виде CSS-классов в выходном HTML, в формате column-<field_name> для каждого элемента <th>. Это может быть использовано, например, для установки ширины столбцов в файле CSS.
  • Django попытается интерпретировать каждый элемент list_display в таком порядке:

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

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

ModelAdmin.list_display_links

Используйте 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),
        )
    

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

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

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

    Вы можете отфильтровать пустые значения, используя EmptyFieldListFilter, что может фильтровать как пустые строки, так и null-значения в зависимости от того, что поле разрешено хранить:

    class BookAdmin(admin.ModelAdmin):
        list_filter = (
            ('title', admin.EmptyFieldListFilter),
        )
    

    Примечание

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

    Примечание

    Поле GenericForeignKey не поддерживается.

    Добавлена в Django 3.1:

    Класс EmptyFieldListFilter был добавлен.

Фильтры списка обычно отображаются только в том случае, если фильтр имеет более одного варианта. Метод has_output() фильтра контролирует, отображается ли он или нет.

Можно указать пользовательский шаблон для рендеринга фильтра списка:

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

См. предоставленный Django стандартный шаблон (admin/filter.html) для конкретного примера.

ModelAdmin.list_max_show_all

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

ModelAdmin.list_per_page

Установите list_per_page для управления количеством элементов, отображаемых на каждой странице списка изменений администратора с постраничной навигацией. По умолчанию это значение равно 100.

ModelAdmin.list_select_related

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

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

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

Если вам нужен более точный контроль, используйте кортеж (или список) в качестве значения для list_select_related. Пустой кортеж предотвратит вызов select_related Django вообще. Любой другой кортеж будет передан напрямую в select_related в качестве параметров. Например:

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

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

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

Примечание

ModelAdmin игнорирует этот атрибут, когда select_related() уже был вызван на списке изменений QuerySet.

ModelAdmin.ordering

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

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

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

Учёт производительности при сортировке

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

Например, если порядок по умолчанию определяется по не уникальному полю name, то список изменений отсортирован по name и pk. Это может быть неэффективно, если у вас много строк и нет индекса на name и 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",)}

При установке указанные поля будут использовать немного JavaScript для заполнения из назначенных полей. Основное применение этой функциональности заключается в автоматическом создании значения для полей SlugField из одного или нескольких других полей. Создаваемое значение формируется путём конкатенации значений исходных полей, а затем преобразования этого результата в допустимый слог (например, замена пробелов на дефисы и приведение ASCII-букв к нижнему регистру).

Предзаполненные поля не изменяются JavaScript после сохранения значения. Обычно нежелательно, чтобы слоги менялись (что привело бы к изменению URL объекта, если слог используется в нём).

prepopulated_fields не принимает поля DateTimeField, ForeignKey, OneToOneField и ManyToManyField.

Изменено в Django 3.2:

В более ранних версиях из создаваемых значений удалялись различные английские стоп-слова.

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 — это список ForeignKey и/или ManyToManyField полей, которые вы хотите изменить на автозаполнение Select2.

По умолчанию административная панель использует интерфейс выпадающего списка (<select>) для этих полей (<select>). Иногда вам не нужно загружать все связанные экземпляры для отображения в выпадающем списке.

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

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

Для предотвращения несанкционированного раскрытия данных пользователи должны иметь разрешение view или change для связанного объекта, чтобы использовать автозаполнение.

Сортировка и постраничный вывод результатов контролируются связанными методами ModelAdmin get_ordering() и get_paginator().

В следующем примере ChoiceAdmin имеет поле автозаполнения для ForeignKey в Question. Результаты отфильтровываются по полю question_text и сортируются по полю date_created:

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

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

Учет производительности при работе с большими наборами данных

Сортировка с использованием ModelAdmin.ordering может привести к проблемам с производительностью, так как сортировка большого набора результатов будет медленной.

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

В таких случаях рекомендуется написать собственную реализацию ModelAdmin.get_search_results() с использованием поиска по полному тексту с индексацией.

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

ModelAdmin.raw_id_fields

По умолчанию Django admin использует интерфейс выпадающего списка (<select>) для полей, которые ForeignKey. Иногда вам не нужно загружать все связанные экземпляры для отображения в выпадающем списке.

raw_id_fields — это список полей, которые вы хотите изменить на виджет Input для ForeignKey или ManyToManyField:

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

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

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

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

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

Поле только для чтения может не только отображать данные из поля модели, но и отображать результат метода модели или метода класса ModelAdmin само по себе. Это очень похоже на то, как работает ModelAdmin.list_display. Это позволяет использовать интерфейс административной панели для отображения статуса редактируемых объектов, например:

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',)

    # description functions like a model field's verbose_name
    @admin.display(description='Address')
    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>")
ModelAdmin.save_as

Установите save_as для активации функции «Сохранить как новый» на формах изменения администратора.

Обычно объекты имеют три варианта сохранения: «Сохранить», «Сохранить и продолжить редактирование» и «Сохранить и добавить другой». Если save_as равно True, «Сохранить и добавить другой» будет заменено кнопкой «Сохранить как новый», которая создаёт новый объект (с новым идентификатором), а не обновляет существующий.

По умолчанию, save_as установлено в False.

ModelAdmin.save_as_continue

Когда используется save_as=True, по умолчанию после сохранения нового объекта происходит переадресация на страницу изменения этого объекта. Если вы установите save_as_continue=False, переадресация будет на страницу списка изменений.

По умолчанию, save_as_continue установлено в True.

ModelAdmin.save_on_top

Установите save_on_top для добавления кнопок сохранения в верхней части форм изменения администратора.

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

По умолчанию, save_on_top установлено в False.

ModelAdmin.search_fields

Установите search_fields для включения поля поиска на странице списка изменений администратора. Это должно быть список имён полей, которые будут проиндексированы, когда кто-то выполнит запрос поиска в этом текстовом поле.

Эти поля должны быть каким-либо типом текстового поля, например CharField или TextField. Вы также можете выполнить связанный поиск по ForeignKey или ManyToManyField с помощью обозначения поиска «follow»:

search_fields = ['foreign_key__related_fieldname']

Например, если у вас есть запись блога с автором, следующее определение включит поиск записей блога по адресу электронной почты автора:

search_fields = ['user__email']

Когда кто-то выполняет поиск в поле поиска администратора, Django разбивает поисковой запрос на слова и возвращает все объекты, которые содержат каждое из слов, без учёта регистра (используя поиск icontains), где каждое слово должно присутствовать хотя бы в одном из search_fields. Например, если search_fields установлено как ['first_name', 'last_name'] и пользователь ищет john lennon, Django выполнит эквивалент этой SQL-строки WHERE:

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

Поисковый запрос может содержать фразы в кавычках с пробелами. Например, если пользователь ищет "john winston" или 'john winston', Django выполнит эквивалент этой SQL-строки WHERE:

WHERE (first_name ILIKE '%john winston%' OR last_name ILIKE '%john winston%')

Если вы не хотите использовать icontains в качестве поиска, вы можете использовать любой поиск, добавив его к полю. Например, вы можете использовать exact, установив search_fields на ['first_name__exact'].

Также доступны некоторые (более старые) сокращения для указания поиска по полю. Вы можете добавить префикс к полю в search_fields с помощью следующих символов, что эквивалентно добавлению __<lookup> к полю:

Префикс Поиск
^ startswith
= iexact
@ search
None icontains

Если вам нужно настроить поиск, вы можете использовать ModelAdmin.get_search_results() для предоставления дополнительного или альтернативного поведения поиска.

Изменено в Django 3.2:

Добавлена поддержка поиска по фразам в кавычках с пробелами.

ModelAdmin.show_full_result_count

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

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

END_OF_DOCUMENT_MARKER
ModelAdmin.sortable_by

По умолчанию страница списка изменений позволяет сортировать по всем полям модели (и вызовам, которые используют аргумент ordering к декоратору display() или имеют атрибут admin_order_field), указанным в list_display.

Если вы хотите отключить сортировку для некоторых столбцов, установите sortable_by в коллекцию (например, list, tuple, или set ) подмножества list_display, которые вы хотите сортировать. Пустая коллекция отключает сортировку для всех столбцов.

Если вам нужно динамически указать этот список, реализуйте метод get_sortable_by() вместо этого.

ModelAdmin.view_on_site

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

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

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

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

Путь к настраиваемому шаблону, используемому response_add(), response_change() и response_delete().

Методы ModelAdmin

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

При переопределении ModelAdmin.save_model() и ModelAdmin.delete_model(), ваш код должен сохранять/удалять объект. Они не предназначены для вето, а позволяют выполнять дополнительные операции.

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

Метод save_model получает HttpRequest, экземпляр модели, экземпляр ModelForm, и булево значение, основанное на том, добавляется или изменяется объект. Переопределение этого метода позволяет выполнять операции до или после сохранения. Вызовите super().save_model() для сохранения объекта с помощью 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)

Метод delete_model получает HttpRequest и экземпляр модели. Переопределение этого метода позволяет выполнять операции до или после удаления. Вызовите super().delete_model() для удаления объекта с помощью Model.delete().

ModelAdmin.delete_queryset(request, queryset)

Метод delete_queryset() получает HttpRequest и QuerySet объектов для удаления. Переопределите этот метод для настройки процесса удаления для действия «удалить выбранные объекты» действие.

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

Метод save_formset получает HttpRequest, родительский экземпляр ModelForm и булево значение, основанное на том, добавляется или изменяется родительский объект.

Например, чтобы прикрепить request.user к каждому изменённому экземпляру модели formset:

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()

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

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 изменяет список отображаемых объектов на те, которые соответствуют предоставленному поисковому запросу. Он принимает запрос, множество, применяющее текущие фильтры, и введённый пользователем поисковый запрос. Возвращает кортеж, содержащий множество, изменённое для реализации поиска, и булево значение, указывающее, могут ли результаты содержать дубликаты.

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

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

Например, чтобы искать по name и age, можно использовать:

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

Эта реализация более эффективна, чем search_fields = ('name', '=age'), которая приводит к строковому сравнения численных полей, например, ... OR UPPER("polls_choice"."votes"::text) = UPPER('4') в PostgreSQL.

ModelAdmin.save_related(request, form, formsets, change)

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

END_OF_DOCUMENT_MARKER ```
ModelAdmin.get_autocomplete_fields(request)

Метод get_autocomplete_fields() получает HttpRequest и должен вернуть list или tuple имён полей, которые будут отображаться с виджетом автозаполнения, как описано выше в разделе ModelAdmin.autocomplete_fields.

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 при добавлении) и должен вернуть dictionary, как описано выше в разделе ModelAdmin.prepopulated_fields.

ModelAdmin.get_list_display(request)

Метод get_list_display получает HttpRequest и должен вернуть list или tuple имён полей, которые будут отображаться на странице списка изменений, как описано выше в разделе ModelAdmin.list_display.

ModelAdmin.get_list_display_links(request, 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)

Метод get_exclude получает HttpRequest и obj редактируемого объекта (или None при добавлении) и должен вернуть список полей, как описано в 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 при добавлении) и должен вернуть список пар из двух элементов, где каждая пара представляет собой набор полей на странице формы администрирования, как описано выше в разделе ModelAdmin.fieldsets.

ModelAdmin.get_list_filter(request)

Метод get_list_filter получает HttpRequest и должен вернуть такой же тип последовательности, как для атрибута list_filter.

ModelAdmin.get_list_select_related(request)

Метод get_list_select_related получает HttpRequest и должен вернуть булево значение или список, как и атрибут ModelAdmin.list_select_related.

ModelAdmin.get_search_fields(request)

Метод get_search_fields получает HttpRequest и должен вернуть такой же тип последовательности, как для атрибута search_fields.

ModelAdmin.get_sortable_by(request)

Метод get_sortable_by() получает HttpRequest и должен вернуть коллекцию (например, list, tuple, или set ) имён полей, которые можно будет сортировать на странице списка изменений.

Его стандартная реализация возвращает значение sortable_by, если оно задано, в противном случае использует get_list_display().

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

class PersonAdmin(admin.ModelAdmin):

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

Метод get_inline_instances получает HttpRequest и obj редактируемого объекта (или None при добавлении) и должен вернуть list или tuple объектов InlineModelAdmin, как описано ниже в разделе InlineModelAdmin. Например, следующее вернёт виджеты без стандартного фильтра по разрешениям на добавление, изменение, удаление и просмотр:

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, иначе при добавлении связанных объектов может возникнуть ошибка «Неверный запрос».

ModelAdmin.get_inlines(request, obj)

Метод get_inlines получает HttpRequest и obj редактируемого объекта (или None при добавлении) и должен вернуть итерируемый объект виджетов. Вы можете переопределить этот метод, чтобы динамически добавлять виджеты на основе запроса или экземпляра модели вместо указания их в 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-адреса перед встроенными.

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

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

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

Поскольку это обычно не то, что вы хотите, 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(), чтобы убедиться, что он не кэшируется, если активен кэширующий middleware.

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

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

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

END_OF_DOCUMENT_MARKER
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)

Также вы можете напрямую вернуть настраиваемый класс ModelForm.

ModelAdmin.get_formsets_with_inlines(request, obj=None)

Возвращает пары (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 в ModelAdmin позволяет переопределить стандартное поле формы для поля foreign key. Например, чтобы вернуть подмножество объектов для этого поля foreign key, основанное на пользователе:

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 для фильтрации поля foreign key Car для отображения только автомобилей, принадлежащих экземпляру User.

Для более сложных фильтров вы можете использовать метод ModelForm.__init__() для фильтрации на основе instance вашей модели (см. Поля, обрабатывающие отношения). Например:

class CountryAdminForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['capital'].queryset = self.instance.cities.all()

class CountryAdmin(admin.ModelAdmin):
    form = CountryAdminForm
ModelAdmin.formfield_for_manytomany(db_field, request, **kwargs)

Как и метод formfield_for_foreignkey, метод formfield_for_manytomany можно переопределить для изменения стандартного поля формы для поля many-to-many. Например, если владелец может владеть несколькими автомобилями, а автомобили могут принадлежать нескольким владельцам — отношение many-to-many — вы могли бы отфильтровать поле foreign key Car для отображения только автомобилей, принадлежащих экземпляру User:

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 можно переопределить для изменения стандартного поля формы для поля, в котором объявлены варианты. Например, если доступные варианты для суперпользователя должны отличаться от вариантов для обычных сотрудников, вы можете поступить следующим образом:

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, установленный на поле формы, будет ограничен только этим полем. Если соответствующее поле в модели имеет заданные варианты, то варианты, предоставляемые форме, должны быть корректным подмножеством этих вариантов, в противном случае отправка формы завершится ошибкой 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 в ModelForm, вы также должны определить атрибут Meta.fields (или атрибут Meta.exclude). Однако, ModelAdmin игнорирует это значение, переопределяя его атрибутом ModelAdmin.list_editable. Самое простое решение — опустить атрибут Meta.model, так как ModelAdmin предоставит правильную модель для использования.

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)

Объекты на странице списка изменений могут быть отфильтрованы с помощью запросов из строки запроса URL. Это то, как работает list_filter, например. Запросы похожи на те, что используются в QuerySet.filter() (например, user__email=user@example.com). Поскольку запросы в строке запроса могут быть изменены пользователем, они должны быть очищены для предотвращения несанкционированного доступа к данным.

Метод lookup_allowed() получает путь запроса из строки запроса (например, 'user__email') и соответствующее значение (например, 'user@example.com') и возвращает булево значение, указывающее, разрешено ли фильтрация списка изменений QuerySet с использованием параметров. Если lookup_allowed() возвращает False, поднимается DisallowedModelAdminLookup (подкласс SuspiciousOperation).

По умолчанию lookup_allowed() разрешает доступ к локальным полям модели, путям полей, используемым в list_filter (но не путям из get_list_filter()), и запросам, необходимым для работы limit_choices_to в raw_id_fields.

Переопределите этот метод для настройки запросов, разрешённых для вашего подкласса ModelAdmin.

ModelAdmin.has_view_permission(request, obj=None)

Должен вернуть True, если просмотр obj разрешён, False в противном случае. Если obj равен None, должен вернуть True или False, чтобы указать, разрешён ли просмотр объектов этого типа в целом (например, False будет означать, что текущий пользователь не имеет разрешения на просмотр ни одного объекта этого типа).

По умолчанию реализация возвращает True, если у пользователя есть разрешение «изменить» или «просмотреть».

ModelAdmin.has_add_permission(request)

Должен вернуть True, если добавление объекта разрешено, False в противном случае.

ModelAdmin.has_change_permission(request, obj=None)

Должен вернуть True, если редактирование obj разрешено, False в противном случае. Если obj равно None, должен вернуть True или False, чтобы указать, разрешено ли редактирование объектов этого типа в целом (например, False будет означать, что текущий пользователь не имеет разрешения на редактирование ни одного объекта этого типа).

ModelAdmin.has_delete_permission(request, obj=None)

Должен вернуть True, если удаление obj разрешено, False в противном случае. Если obj равно None, должен вернуть True или False, чтобы указать, разрешено ли удаление объектов этого типа в целом (например, False будет означать, что текущий пользователь не имеет разрешения на удаление ни одного объекта этого типа).

END_OF_DOCUMENT_MARKER
ModelAdmin.has_module_permission(request)

Должно возвращать True, если модуль отображается на странице индекса админки и доступ к странице индекса модуля разрешён, False в противном случае. По умолчанию использует User.has_module_perms(). Переопределение не ограничивает доступ к просмотрам, добавлению, изменению или удалению представлений, has_view_permission(), has_add_permission(), has_change_permission() и has_delete_permission() следует использовать для этого.

ModelAdmin.get_queryset(request)

Метод get_queryset на ModelAdmin возвращает 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)

Обработчик для настройки процесса удаления в представлении delete_view() и действия «удалить выбранные» действие.

Аргумент objs — однородный итерируемый объект (QuerySet или список экземпляров модели) для удаления, а request — HttpRequest.

Этот метод должен возвращать 4-х кортеж (deleted_objects, model_count, perms_needed, protected).

deleted_objects — список строк, представляющих все объекты, которые будут удалены. Если есть связанные объекты для удаления, список вложен и включает эти связанные объекты. Список отформатирован в шаблоне с использованием фильтра unordered_list.

model_count — словарь, сопоставляющий множественное число verbose_name_plural каждой модели с количеством объектов, которые будут удалены.

perms_needed — набор единственного числа verbose_name моделей, для которых у пользователя нет разрешения на удаление.

protected — список строк, представляющих все защищённые связанные объекты, которые не могут быть удалены. Список отображается в шаблоне.

Другие методы

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

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

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

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

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 из обработчика маршрутизации URL-адреса приложения админки для отрисовки страниц, которые обрабатывают операции 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

Django админка использует библиотеку jQuery.

Для предотвращения конфликтов с пользовательскими скриптами или библиотеками, jQuery Django (версия 3.5.1) имеет пространство имён django.jQuery. Если вы хотите использовать jQuery в собственном JavaScript-коде админки без включения второй копии, вы можете использовать объект django.jQuery в представлениях списка изменений и добавления/редактирования. Кроме того, собственные формы или виджеты админки, зависящие от django.jQuery, должны указывать js=['admin/js/jquery.init.js', …] при определении медиа-активов форм.

Изменено в Django 3.1:

jQuery был обновлён с версии 3.4.1 до 3.5.1.

Класс ModelAdmin по умолчанию требует jQuery, поэтому нет необходимости добавлять jQuery в список медиа-ресурсов вашей ModelAdmin, если у вас нет особой потребности. Например, если вам необходимо, чтобы библиотека jQuery находилась в глобальном пространстве имён (например, при использовании сторонних плагинов jQuery) или вам нужна более новая версия jQuery, вам придётся включить свою собственную копию.

Django предоставляет как нескомпрессированные, так и «минифицированные» версии jQuery, как jquery.js и jquery.min.js соответственно.

ModelAdmin и InlineModelAdmin имеют свойство media, которое возвращает список Media объектов, хранящих пути к JavaScript-файлам для форм и/или наборов форм. Если DEBUG равно True, оно вернёт нескомпрессированные версии различных JavaScript-файлов, включая jquery.js; в противном случае вернёт «минифицированные» версии.

Добавление пользовательской валидации в админ-панель

Вы также можете добавить пользовательскую валидацию данных в админ-панели. Автоматический интерфейс админки использует django.forms, а класс ModelAdmin позволяет определить собственную форму:

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 , иначе всё может сломаться. См. документацию форм по пользовательской валидации и, более конкретно, примечания по валидации форм моделей для получения дополнительной информации.

InlineModelAdmin объекты

class InlineModelAdmin
class TabularInline
class StackedInline

Интерфейс админки позволяет редактировать модели на одной странице с родительской моделью. Они называются встраиваниями. Предположим, у вас есть эти две модели:

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)

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

from django.contrib import admin

class BookInline(admin.TabularInline):
    model = Book

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

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

  • TabularInline
  • StackedInline

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

InlineModelAdmin опции

InlineModelAdmin наследует многие функции ModelAdmin и добавляет свои собственные (общие функции фактически определены в суперклассе BaseModelAdmin). Общие функции:

  • form
  • fieldsets
  • fields
  • formfield_overrides
  • exclude
  • filter_horizontal
  • filter_vertical
  • ordering
  • prepopulated_fields
  • get_fieldsets()
  • get_queryset()
  • radio_fields
  • readonly_fields
  • raw_id_fields
  • formfield_for_choice_field()
  • formfield_for_foreignkey()
  • formfield_for_manytomany()
  • has_module_permission()

Класс InlineModelAdmin добавляет или настраивает:

InlineModelAdmin.model

Модель, используемая встраиванием. Это обязательно.

InlineModelAdmin.fk_name

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

InlineModelAdmin.formset

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

InlineModelAdmin.form

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

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

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

InlineModelAdmin.classes

Список или кортеж дополнительных CSS-классов для применения к набору элементов управления, который отображается для встраиваний. По умолчанию None. Как и с классами, настроенными в fieldsets, встраивания с классом collapse будут изначально свёрнуты, а в заголовке будет небольшая ссылка «показать».

InlineModelAdmin.extra

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

Для пользователей с браузерами, поддерживающими JavaScript, предоставляется ссылка «Добавить ещё», чтобы можно было добавить любое количество дополнительных строк помимо тех, что были предоставлены в результате аргумента 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. Иногда вы не хотите нести издержки, связанные с выбором всех связанных экземпляров для отображения в выпадающем списке.

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.

InlineModelAdmin.show_change_link

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

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

Возвращает класс BaseInlineFormSet для использования в админских представлениях добавления/изменения. obj — это родительский объект, который редактируется, или None при добавлении нового родителя. См. пример для 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)

Должен вернуть True , если добавление объекта в строку разрешено, False в противном случае. obj — это родительский объект, который редактируется, или None при добавлении нового родителя.

InlineModelAdmin.has_change_permission(request, obj=None)

Должен вернуть True , если редактирование объекта в строке разрешено, False в противном случае. obj — это родительский объект, который редактируется.

InlineModelAdmin.has_delete_permission(request, obj=None)

Должен вернуть True , если удаление объекта в строке разрешено, False в противном случае. obj — это родительский объект, который редактируется.

Примечание

Аргумент obj , переданный методам InlineModelAdmin , — это родительский объект, который редактируется, или None при добавлении нового родителя.

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

Иногда возможно иметь более одного внешнего ключа к той же модели. Возьмем, к примеру, такую модель:

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")

Если вы хотите отобразить строку на страницах добавления/изменения админки 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,
    ]

Работа с моделями many-to-many

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

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

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')

Если вы хотите отобразить отношения many-to-many с помощью строки, вы можете сделать это, определив объект 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 — это ссылка на модель, которая управляет отношением many-to-many. Эта модель автоматически создаётся Django при определении поля many-to-many.

Во-вторых, необходимо вручную исключить поле members . Django отображает виджет админки для поля many-to-many в модели, которая определяет отношение (в данном случае, Group). Если вы хотите использовать модель строки для представления отношения many-to-many, вы должны сказать админке Django, что этот виджет не отображать — иначе у вас на странице админки будут два виджета для управления отношением.

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

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

Работа с промежуточными моделями many-to-many

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

Однако, мы по-прежнему хотим иметь возможность редактировать эту информацию в строке. К счастью, это можно сделать с помощью встроенных моделей администрирования. Предположим, у нас есть следующие модели:

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

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

Теперь создайте представления администрирования для моделей 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.

Использование универсальных связей как встроенных элементов

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

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 для более подробной информации.

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

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

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

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

Для переопределения одного или нескольких из них сначала создайте каталог admin в каталоге templates вашего проекта. Это может быть любой из каталогов, указанных в опции DIRS бэкенда DjangoTemplates в настройке TEMPLATES. Если вы настраивали опцию 'loaders', убедитесь, что 'django.template.loaders.filesystem.Loader' предшествует 'django.template.loaders.app_directories.Loader', чтобы система загрузки шаблонов сначала находила ваши пользовательские шаблоны, а затем шаблоны, включённые с 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">{% translate "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">{% translate "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

Для тех шаблонов, которые нельзя переопределить таким образом, вы всё ещё можете переопределить их для всего проекта, поместив новую версию в каталог templates/admin вашего проекта. Это особенно полезно для создания пользовательских страниц 404 и 500.

Примечание

Некоторые шаблоны администрирования, такие как change_list_results.html , используются для рендеринга пользовательских тегов включения. Их можно переопределить, но в таких случаях вам, вероятно, лучше создать собственную версию интересующего тега и дать ему другое имя. Таким образом, вы сможете использовать его выборочно.

Шаблоны корневой страницы и входа

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

Поддержка оформления

Новое в Django 3.2.

Администрирование использует переменные CSS для определения цветов. Это позволяет изменять цвета без необходимости переопределения многих отдельных правил CSS. Например, если бы вы предпочли фиолетовый вместо синего, вы могли бы добавить переопределение шаблона admin/base.html в свой проект:

{% extends 'admin/base.html' %}

{% block extrahead %}{{ block.super }}
<style>
:root {
  --primary: #9774d5;
  --secondary: #785cab;
  --link-fg: #7c449b;
  --link-selected-fg: #8f5bb2;
}
</style>
{% endblock %}

Определён тёмный стиль, и он применяется, учитывая prefers-color-scheme медиа запрос.

Список переменных CSS определён в django/contrib/admin/static/admin/css/base.css.

AdminSite объекты

class AdminSite(name='admin')

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

Если вы хотите настроить сайт администрирования по умолчанию, вы можете переопределить его.

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

AdminSite атрибуты

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

AdminSite.site_header

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

AdminSite.site_title

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

AdminSite.site_url

Адрес ссылки «Просмотр сайта» в верхней части каждой страницы админки. По умолчанию, site_url равен /. Установите его в None чтобы удалить ссылку.

Для сайтов, работающих на подпути, метод each_context() проверяет, установлено ли текущему запросу значение request.META['SCRIPT_NAME'] и использует это значение, если site_url не установлено на что-то отличное от /.

AdminSite.index_title

Текст, который будет отображаться вверху страницы индекса админки (строка). По умолчанию, это «Администрирование сайта».

AdminSite.index_template

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

AdminSite.app_index_template

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

AdminSite.empty_value_display

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

AdminSite.enable_nav_sidebar
Новое в Django 3.1.

Булево значение, определяющее, отображать ли боковую панель навигации на больших экранах. По умолчанию, оно установлено в True.

AdminSite.final_catch_all_view
Новое в Django 3.2.

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

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

Не рекомендуется устанавливать это значение в False так как представление защищает от потенциальной проблемы конфиденциальности перечисления моделей.

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: отслеживание dict, add, change, и delete разрешений
    • 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)

Регистрирует указанный класс модели (или итерируемый список классов) с указанным admin_class. По умолчанию, admin_class используется ModelAdmin (опции админки по умолчанию). Если заданы ключевые аргументы — например, list_display — они будут применены как опции к классу админки.

Вызывает ImproperlyConfigured, если модель является абстрактной, и django.contrib.admin.sites.AlreadyRegistered если модель уже зарегистрирована.

AdminSite.unregister(model_or_iterable)

Дерегистрирует указанный класс модели (или итерируемый список классов).

Вызывает django.contrib.admin.sites.NotRegistered если модель не зарегистрирована.

Привязка экземпляров AdminSite к вашему URLconf

Последний шаг в настройке Django админки — привязка экземпляра AdminSite к вашему URLconf. Сделайте это, указав определённый URL на метод AdminSite.urls. Использовать 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

Если вы хотите создать свою админку с настраиваемым поведением, вы можете создать подкласс AdminSite и переопределить или добавить что угодно. Затем создайте экземпляр вашего подкласса AdminSite (так же, как вы бы создавали любой другой класс Python) и зарегистрируйте ваши модели и подклассы ModelAdmin с ним вместо стандартной админки. Наконец, обновите myproject/urls.py для ссылки на ваш подкласс AdminSite.

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),
]

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

Переопределение стандартной админки

Вы можете переопределить стандартную django.contrib.admin.site, установив атрибут default_site пользовательского AppConfig на путь импорта дочернего класса AdminSite или вызываемого объекта, возвращающего экземпляр сайта.

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

Вы можете создать несколько экземпляров администраторского сайта на одном веб-сайте, работающем на Django. Создайте несколько экземпляров AdminSite и разместите каждый из них по разному URL.

В этом примере URL /basic-admin/ и /advanced-admin/ отображают отдельные версии администраторского сайта — используя экземпляры AdminSite myproject.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() для добавления шаблона для вашего нового представления.

Примечание

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

Добавление функции сброса пароля

Вы можете добавить функцию сброса пароля к администраторскому сайту, добавив несколько строк в вашу URLconf. В частности, добавьте эти четыре шаблона:

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/, перед строкой, содержащей приложение 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

Подробное описание изменения. В случае редактирования, сообщение содержит список изменённых полей. Администраторский сайт Django форматирует это содержимое как JSON-структуру, так что get_change_message() может пересобрать сообщение, переведённое на текущий язык пользователя. Несмотря на это, пользовательский код может установить это как обычную строку. Тем не менее, рекомендуется использовать метод get_change_message() для получения этого значения вместо непосредственного доступа к нему.

Методы LogEntry

LogEntry.get_edited_object()

Сокращение, которое возвращает сохранённый объект.

LogEntry.get_change_message()

Форматирует и переводит change_message на текущий язык пользователя. Сообщения, созданные до Django 1.10, всегда будут отображаться на языке, на котором они были записаны.

Обратное преобразование URL администратора

Когда AdminSite развернут, к предоставляемым им представлениям можно получить доступ с помощью системы обратного преобразования URL Django системы обратного преобразования URL.

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

Страница Имя URL Параметры
Индекс index
Вход login
Выход logout
Изменение пароля password_change
Изменение пароля завершено password_change_done
JavaScript i18n 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, и в пространстве имён экземпляра, соответствующем имени экземпляра сайта.

Таким образом — если вам нужно получить ссылку на представление Изменить для конкретного объекта 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, и обычно предоставляется представлениями администратора для текущей модели.

Декоратор display

display(*, boolean=None, ordering=None, description=None, empty_value=None)
New in Django 3.2.

This decorator can be used for setting specific attributes on custom display functions that can be used with list_display or readonly_fields:

@admin.display(
    boolean=True,
    ordering='-publish_date',
    description='Is Published?',
)
def is_published(self, obj):
    return obj.publish_date is not None

This is equivalent to setting some attributes (with the original, longer names) on the function directly:

def is_published(self, obj):
    return obj.publish_date is not None
is_published.boolean = True
is_published.admin_order_field = '-publish_date'
is_published.short_description = 'Is Published?'

Also note that the empty_value decorator parameter maps to the empty_value_display attribute assigned directly to the function. It cannot be used in conjunction with boolean – they are mutually exclusive.

Use of this decorator is not compulsory to make a display function, but it can be useful to use it without arguments as a marker in your source to identify the purpose of the function:

@admin.display
def published_year(self, obj):
    return obj.publish_date.year

In this case it will add no attributes to the function.

The staff_member_required decorator

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

This decorator is used on the admin views that require authorization. A view decorated with this function will having the following behavior:

  • If the user is logged in, is a staff member (User.is_staff=True), and is active (User.is_active=True), execute the view normally.
  • Otherwise, the request will be redirected to the URL specified by the login_url parameter, with the originally requested path in a query string variable specified by redirect_field_name. For example: /admin/login/?next=/admin/polls/question/3/.

Example usage:

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

@staff_member_required
def my_view(request):
    ...

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/3.2/ref/contrib/admin/index/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API