Сайт администратора 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.

    Changed in 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. Hook the admin’s URLs into your URLconf.

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

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

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

Другие темы

См.также

Информацию об обслуживании статических файлов (изображений, 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')

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

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

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

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

from django.db import models

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

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

from django.contrib import admin

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

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

Поскольку модель 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, за исключением того, что callables не принимаются. Имена методов model и model admin будут использоваться, только если они перечислены в 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'),
    }
    

    Два полезных класса, определяемых таблицей стилей сайта администратора по умолчанию, это collapse и wide. Наборы полей со стилем collapse будут изначально свернуты в админке и заменены маленькой ссылкой «click to expand». Наборы полей со стилем 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

В приведенном выше примере поле «возраст» будет исключено, но поле «имя» будет включено в созданную форму.

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:

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

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

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

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

    from django.contrib import admin
    from django.db import models
    
    class Person(models.Model):
        name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        def decade_born_in(self):
            return '%d’s' % (self.birthday.year // 10 * 10)
        decade_born_in.short_description = 'Birth decade'
    
    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)
    
        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, вы можете настроить заголовок колонки, добавив атрибут 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')
    
        def birth_date_view(self, obj):
             return obj.birth_date
    
        birth_date_view.empty_value_display = 'unknown'
    
  • Если заданная строка является методом модели, ModelAdmin или вызываемым методом, который возвращает True, False или None, Django отобразит красивую иконку «yes», «no» или «unknown», если вы зададите методу атрибут boolean, значение которого True.

    Вот полный пример модели:

    from django.contrib import admin
    from django.db import models
    
    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        def born_in_fifties(self):
            return 1950 <= self.birthday.year < 1960
        born_in_fifties.boolean = True
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'born_in_fifties')
    
  • Метод __str__() так же действителен в list_display, как и любой другой метод моделирования, так что это совершенно нормально:

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

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

    Например:

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

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

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

    colored_first_name.admin_order_field = '-first_name'
    

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

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

    Query expressions может использоваться в admin_order_field. Например:

    from django.db.models import Value
    from django.db.models.functions import Concat
    
    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
    
        def full_name(self):
            return self.first_name + ' ' + self.last_name
        full_name.admin_order_field = Concat('first_name', Value(' '), 'last_name')
    
  • Элементы list_display также могут быть свойствами. Однако обратите внимание, что из-за особенностей работы свойств в Python, установка short_description или admin_order_field на свойство возможна только при использовании функции property() и не при использовании декоратора @property.

    Например:

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

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

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

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

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

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

  • Установите значение None, чтобы вообще не получать ссылок.

  • Установите его в список или кортеж полей (в том же формате, что и list_display), столбцы которых вы хотите преобразовать в ссылки.

    Вы можете указать одно или много полей. До тех пор, пока поля отображаются в list_display, Django неважно, сколько (или сколько мало) полей связано. Единственное требование - если вы хотите использовать list_display_links таким образом, вы должны определить list_display.

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

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

В этом примере сетка страницы списка изменений не будет иметь ссылок:

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

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

Примечание

list_editable взаимодействует с парой других опций особым образом; вам следует обратить внимание на следующие правила:

  • Любое поле в list_editable должно быть также в list_display. Вы не можете редактировать поле, которое не отображается!
  • Одно и то же поле не может быть указано в list_editable и list_display_links - поле не может быть одновременно формой и ссылкой.

Если одно из этих правил нарушено, вы получите ошибку валидации.

ModelAdmin.list_filter

Установите list_filter для активации фильтров в правой боковой панели страницы списка изменений в админке, как показано на следующем снимке экрана:

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

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

  • имя поля, где указанное поле должно быть либо BooleanField, CharField, DateField, DateTimeField, IntegerField, ForeignKey или ManyToManyField, например:

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

    Имена полей в list_filter также могут охватывать отношения с помощью поиска __, например:

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

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

    Примечание

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

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

    Также в качестве удобства, объект ModelAdmin передается методу lookups, например, если вы хотите основывать поиск на доступных данных:

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

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

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

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

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

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

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

    Примечание

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

    Примечание

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

    New in 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.

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

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

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

Если вам нужен более тонкий контроль, используйте кортеж (или список) в качестве значения для list_select_related. Пустой кортеж не позволит Django вызвать select_related вообще. Любой другой кортеж будет передан непосредственно в 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 из одного или нескольких других полей. Генерируемое значение получается путем конкатенации значений исходных полей, а затем путем преобразования этого результата в правильный slug (например, замена тире на пробелы; строчные буквы ASCII; удаление различных английских стоп-слов, таких как „a“, „an“, „as“ и подобных).

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

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

ModelAdmin.preserve_filters

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

ModelAdmin.radio_fields

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

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

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

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

Упорядочивание и пагинация результатов контролируются связанными методами ModelAdminget_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 используется интерфейс выбора (<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',)

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

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

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

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

По умолчанию 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» API поиска:

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

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

Обратите внимание, что поскольку термины запроса разделяются и AND, как описано ранее, поиск с помощью exact работает только с одним поисковым словом, поскольку два или более слов не могут быть точным совпадением, если только все слова не одинаковые.

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

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

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

ModelAdmin.show_full_result_count

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

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

ModelAdmin.sortable_by

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

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

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

ModelAdmin.view_on_site

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

Это значение может быть либо булевым флагом, либо вызываемым объектом. Если True (по умолчанию), то для генерации url будет использоваться метод объекта get_absolute_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 для отображения страницы подтверждения при удалении одного или нескольких объектов. См. actions documentation.

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 объектов для удаления. Переопределите этот метод, чтобы настроить процесс удаления для «удаления выбранных объектов» action.

ModelAdmin.save_formset(request, form, formset, change)[исходный код]

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

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

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

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

ModelAdmin.get_ordering(request)

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

class PersonAdmin(admin.ModelAdmin):

    def get_ordering(self, request):
        if request.user.is_superuser:
            return ['name', 'rank']
        else:
            return ['name']
ModelAdmin.get_search_results(request, queryset, search_term)[исходный код]

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

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

Этот метод может быть переопределен вашим собственным методом поиска. Например, вы можете искать по целочисленному полю или использовать внешний инструмент, такой как Solr или Haystack. Вы должны установить, могут ли изменения queryset, осуществляемые вашим методом поиска, внести дубликаты в результаты, и вернуть 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.

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

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.

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

ModelAdmin.get_list_filter(request)[исходный код]

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

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

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

Методу 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, зарегистрированная выше, страдает от двух проблем:

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

Поскольку это обычно не то, что вам нужно, Django предоставляет удобную обертку для проверки разрешений и пометки представления как некэшируемого. Эта обертка AdminSite.admin_view() (т.е. self.admin_site.admin_view внутри экземпляра ModelAdmin); используйте ее так:

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

Обратите внимание на обернутый вид в пятой строке сверху:

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

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

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

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

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

ModelAdmin.get_form(request, obj=None, **kwargs)[исходный код]

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

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

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

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

ModelAdmin.get_formsets_with_inlines(request, obj=None)[исходный код]

Создает пары (FormSet, InlineModelAdmin) для использования в представлениях добавления и изменения администратора.

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

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

Здесь используется экземпляр HttpRequest для фильтрации поля внешнего ключа Car, чтобы отобразить только автомобили, принадлежащие экземпляру 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 может быть переопределен для изменения поля формы по умолчанию для поля «многие ко многим». Например, если владелец может владеть несколькими автомобилями, а автомобили могут принадлежать нескольким владельцам - отношение «многие ко многим» - вы можете отфильтровать поле внешнего ключа 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 будет интерпретировано как означающее, что текущему пользователю запрещено удалять любой объект данного типа).

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. См. custom ModelAdmin example.

Аргументы с ключевыми словами позволяют изменить уровень сообщения, добавить дополнительные 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() и «удалить выбранное» action.

Аргумент 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 представление для страницы, которая показывает историю модификаций для данного экземпляра модели.

В отличие от методов типа hook 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 documentation.

ModelAdmin определения активов

Бывают случаи, когда вы хотите добавить немного CSS и/или JavaScript в представления добавления/изменения. Этого можно добиться, используя внутренний класс Media на вашем ModelAdmin:

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

staticfiles app добавляет STATIC_URL (или MEDIA_URL, если STATIC_URL равно None) к любым путям активов. Применяются те же правила, что и для regular asset definitions on forms.

jQuery

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

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

Changed in Django 3.0:

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

Changed in 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, иначе все может сломаться. См. документацию forms по custom validation и, более конкретно, model form validation notes для получения дополнительной информации.

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 и это:

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

InlineModelAdmin опции

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

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

InlineModelAdmin.model

Модель, которую использует инлайн. Требуется.

InlineModelAdmin.fk_name

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

InlineModelAdmin.formset

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

InlineModelAdmin.form

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

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

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

InlineModelAdmin.classes

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

InlineModelAdmin.extra

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

Для пользователей браузеров с поддержкой 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.

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

Работа с моделями «многие-ко-многим

По умолчанию виджеты администратора для отношений «многие-ко-многим» будут отображаться на той модели, которая содержит фактическую ссылку на ManyToManyField. В зависимости от вашего определения ModelAdmin, каждое поле «многие-ко-многим» в вашей модели будет представлено стандартным 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')

Если вы хотите отобразить отношения «многие ко многим» с помощью инлайна, вы можете сделать это, определив объект InlineModelAdmin для отношения:

from django.contrib import admin

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

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

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

В этом примере стоит отметить две особенности.

Во-первых, класс MembershipInline ссылается на Group.members.through. Атрибут through является ссылкой на модель, которая управляет отношением «многие-ко-многим». Эта модель автоматически создается Django, когда вы определяете поле «многие-ко-многим».

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

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

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

Работа с моделями посредников «многие-ко-многим

Когда вы указываете промежуточную модель с помощью аргумента 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 documentation.

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

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

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

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

Шаблоны корня и входа в систему

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

AdminSite объекты

class AdminSite(name='admin')[исходный код]

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

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

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

AdminSite атрибуты

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

AdminSite.site_header

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

AdminSite.site_title

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

AdminSite.site_url

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
New in Django 3.1.

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

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

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

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

    • object_name: имя класса модели
    • name: множественное имя модели
    • perms: разрешение dict, отслеживающее add, change, delete и view
    • 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 для целей reversing them. Это необходимо только в том случае, если вы используете более одного 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/, перед строкой, которая включает само приложение администратора).

Наличие 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 reversing system Django.

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

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

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

Страница Имя URL Параметры
Changelist {{ 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, а также в пространстве имен экземпляра, соответствующем имени экземпляра Site.

Итак - если вы хотите получить ссылку на представление Change для определенного объекта Choice (из приложения polls) в администраторе по умолчанию, вы вызовете:

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

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

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

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

Для более подробной информации смотрите документацию по reversing namespaced URLs.

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

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

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

Декоратор staff_member_required

staff_member_required(redirect_field_name='next', login_url='admin:login')[исходный код]

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

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

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

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

@staff_member_required
def my_view(request):
    ...
Вернуться на верх