Spec-Zone.ru › Django 1.9

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

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

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

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

Обзор

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

Для справки, вот требования:

  1. Добавьте 'django.contrib.admin' в свой параметр INSTALLED_APPS.
  2. Администрирование имеет четыре зависимости - django.contrib.auth, django.contrib.contenttypes, django.contrib.messages и django.contrib.sessions. Если эти приложения отсутствуют в вашем списке INSTALLED_APPS, добавьте их.
  3. Добавьте django.contrib.auth.context_processors.auth и django.contrib.messages.context_processors.messages к параметру 'context_processors' бэкэнда DjangoTemplates, определенного в вашем TEMPLATES, а также django.contrib.auth.middleware.AuthenticationMiddleware и django.contrib.messages.middleware.MessageMiddleware к MIDDLEWARE_CLASSES. (Все они активны по умолчанию, поэтому вам нужно это сделать только если вы вручную изменили настройки.)
  4. Определите, какие из моделей вашего приложения должны быть доступны для редактирования в интерфейсе администрирования.
  5. Для каждой из этих моделей необязательно создать класс ModelAdmin, который инкапсулирует настраиваемые функции администрирования и параметры для этой конкретной модели.
  6. Инициализируйте экземпляр AdminSite и сообщите ему о каждой из ваших моделей и классах ModelAdmin.
  7. Подключите экземпляр AdminSite к вашей URLconf.

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

Другие темы

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

См. также

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

Возникли проблемы? Попробуйте ЧАВО: Администрирование.

Объекты ModelAdmin

Класс class ModelAdmin [source]

Класс 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.admin.sites.site) [source]

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

from django.contrib import admin
from .models import Author

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

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

from django.contrib import admin
from .models import Author, Reader, Editor
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). Если вы используете Python 3 и не беспокоитесь о поддержке Python 2, вы можете использовать super().__init__(*args, **kwargs) . В противном случае вам нужно использовать admin.site.register() вместо этого декоратора.

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

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

Класс class apps.AdminConfig

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

Класс class apps.SimpleAdminConfig

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

Функция autodiscover() [source]

Эта функция пытается импортировать модуль 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 использует 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, может содержать только имена полей в модели или в форме, указанной в form. Она может содержать вызываемые объекты только в том случае, если они перечислены в 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 будут изначально свёрнуты в админпанели и заменены небольшой ссылкой «нажать, чтобы развернуть». Наборы полей со стилем 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.db import models
from django.contrib import admin

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

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

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

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

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

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

ModelAdmin.inlines

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

ModelAdmin.list_display

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

Пример:

list_display = ('first_name', 'last_name')

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

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

    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'
    
  • Строка, представляющая атрибут в модели. Это ведет себя почти также как вызываемый объект, но self в этом контексте — экземпляр модели. Вот полный пример модели:

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

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

  • Если поле является ForeignKey, Django отобразит __str__() (__unicode__() в Python 2) связанного объекта.
  • ManyToManyField поля не поддерживаются, потому что это потребовало бы выполнения отдельного SQL-запроса для каждой строки в таблице. Если вы все же хотите это сделать, добавьте в модель пользовательский метод, и добавьте имя этого метода в list_display. (Подробнее о пользовательских методах в list_display см. ниже.)
  • Если поле является BooleanField или NullBooleanField, Django отобразит красивую иконку «включено» или «выключено» вместо True или False.
  • Если указанная строка является методом модели, ModelAdmin или вызываемым объектом, Django по умолчанию экранирует вывод с помощью HTML. Чтобы экранировать пользовательский ввод и разрешить свои собственные неэкранированные теги, используйте format_html().

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

    from django.db import models
    from django.contrib import admin
    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')
    

    Устаревшее с версии 1.9: В более старых версиях вы могли добавить атрибут allow_tags к методу, чтобы предотвратить автоматическое экранирование. Этот атрибут устарел, так как безопаснее использовать format_html(), format_html_join() или mark_safe().

  • Если значение поля равно 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'
    

    Добавлена возможность настройки empty_value_display.

  • Если указанная строка является методом модели, ModelAdmin или вызываемым объектом, возвращающим True или False, Django отобразит красивую иконку «включено» или «выключено», если вы зададите методу атрибут boolean со значением True.

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

    from django.db import models
    from django.contrib import admin
    
    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        def born_in_fifties(self):
            return self.birthday.strftime('%Y')[:3] == '195'
        born_in_fifties.boolean = True
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'born_in_fifties')
    
  • Метод __str__() (__unicode__() в Python 2) так же допустим в list_display как и любой другой метод модели, поэтому вполне допустимо сделать это:

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

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

    Например:

    from django.db import models
    from django.contrib import admin
    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'
    
  • Элементы list_display также могут быть свойствами. Обратите внимание, что из-за того, как работают свойства в Python, задание short_description для свойства возможно только при использовании функции 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"
    
        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 , будет использовано поле модели.

ModelAdmin.list_display_links

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

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

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

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

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

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

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

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

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

Примечание

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

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

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

ModelAdmin.list_filter

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

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

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

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

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

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

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

    from datetime import date
    
    from django.contrib import admin
    from django.utils.translation import ugettext_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(AuthDecadeBornListFilter, self).lookups(request, model_admin)
    
        def queryset(self, request, queryset):
            if request.user.is_superuser:
                return super(AuthDecadeBornListFilter, self).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 пользователями, которые написали книгу, вместо того, чтобы перечислить всех пользователей.

    Примечание

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

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

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

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

ModelAdmin.list_max_show_all

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

ModelAdmin.list_per_page

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

ModelAdmin.list_select_related

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

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

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

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

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

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

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

ModelAdmin.ordering

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

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

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

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 полей из одного или нескольких других полей. Сгенерированное значение получается путём конкатенации значений исходных полей, а затем преобразованием этого результата в корректный «сlag» (например, замены пробелов дефисами).

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

ModelAdmin.preserve_filters

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

ModelAdmin.radio_fields

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

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

У вас есть выбор использования HORIZONTAL или VERTICAL из модуля django.contrib.admin.

Не включайте поле в radio_fields если оно не ForeignKey или не имеет choices установленным.

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

По умолчанию save_as имеет значение False.

ModelAdmin.save_on_top

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

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

По умолчанию save_on_top имеет значение False.

ModelAdmin.search_fields

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

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

search_fields = ['foreign_key__related_fieldname']

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

search_fields = ['user__email']

Когда пользователь выполняет поиск в поле поиска администратора, Django разделяет запрос на слова и возвращает все объекты, содержащие каждое из слов, без учёта регистра, где каждое слово должно быть в хотя бы одном из 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%')

Для более быстрого и/или более ограниченного поиска добавьте префикс к имени поля с оператором:

^

Используйте оператор ‘^’ для соответствия, начиная с начала поля. Например, если search_fields имеет значение ['^first_name', '^last_name'] и пользователь ищет john lennon, Django выполнит эквивалент следующего SQL-запроса WHERE:

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

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

=

Используйте оператор ‘=’ для регистронезависимого точного соответствия. Например, если 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')

Обратите внимание, что входной запрос разделяется пробелами, поэтому, следуя этому примеру, в настоящее время невозможно искать все записи, в которых first_name точно равно 'john winston' (содержащее пробел).

@
Используйте оператор ‘@’ для выполнения полнотекстового поиска. Это похоже на метод поиска по умолчанию, но использует индекс. В настоящее время доступно только для MySQL.

Если вам нужно настроить поиск, вы можете использовать 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.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.core.urlresolvers import reverse

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

Дополнительные параметры шаблонов

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

ModelAdmin.add_form_template

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

ModelAdmin.change_form_template

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

ModelAdmin.change_list_template

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

ModelAdmin.delete_confirmation_template

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

ModelAdmin.delete_selected_confirmation_template

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

ModelAdmin.object_history_template

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

Методы ModelAdmin

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

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

ModelAdmin.save_model(request, obj, form, change) [source]

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

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

from django.contrib import admin

class ArticleAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.user = request.user
        obj.save()
ModelAdmin.delete_model(request, obj) [source]

Метод delete_model получает HttpRequest и экземпляр модели. Используйте этот метод для выполнения предопераций или послеопераций удаления.

ModelAdmin.save_formset(request, form, formset, change) [source]

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

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

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

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

ModelAdmin.get_ordering(request)

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

class PersonAdmin(admin.ModelAdmin):

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

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

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

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

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

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

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

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

ModelAdmin.save_related(request, form, formsets, change) [source]

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

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) [source]

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

ModelAdmin.get_list_display_links(request, list_display) [source]

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

ModelAdmin.get_fields(request, obj=None) [source]

Метод 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) [source]

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

ModelAdmin.get_list_select_related(request) [source]

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

ModelAdmin.get_search_fields(request) [source]

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

ModelAdmin.get_inline_instances(request, obj=None) [source]

Метод get_inline_instances получает HttpRequest и obj, которые редактируются (или None на форме добавления), и должен вернуть список или кортеж объектов 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_urls() [source]

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

class MyModelAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super(MyModelAdmin, self).get_urls()
        my_urls = [
            url(r'^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(MyModelAdmin, self).get_urls()
        my_urls = [
            url(r'^my_view/$', self.admin_site.admin_view(self.my_view))
        ]
        return my_urls + urls

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

url(r'^my_view/$', self.admin_site.admin_view(self.my_view))

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

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

url(r'^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) [source]

Возвращает класс 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(MyModelAdmin, self).get_form(request, obj, **kwargs)

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

ModelAdmin.get_formsets_with_inlines(request, obj=None) [source]

Возвращает пары (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 isinstance(inline, MyInline) and obj is None:
                continue
            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(MyModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

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

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(MyModelAdmin, self).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(MyModelAdmin, self).formfield_for_choice_field(db_field, request, **kwargs)

Примечание

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

ModelAdmin.get_changelist(request, **kwargs) [source]

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

ModelAdmin.get_changelist_form(request, **kwargs) [source]

Возвращает класс 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) [source]

Возвращает класс 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(MyModelAdmin, self).get_changelist_formset(request, **kwargs)
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_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(MyModelAdmin, self).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) [source]

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

Ключевые аргументы позволяют изменить уровень сообщения, добавить дополнительные теги CSS или тихо провалиться, если contrib.messages фреймворк не установлен. Эти ключевые аргументы соответствуют аргументам функции django.contrib.messages.add_message(); см. документацию этой функции для получения более подробной информации. Отличие состоит в том, что уровень может быть передан в виде текстовой метки помимо целого числа/константы.

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

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

ModelAdmin.response_add(request, obj, post_url_continue=None) [source]

Определяет HttpResponse для стадии add_view().

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

ModelAdmin.response_change(request, obj) [source]

Определяет HttpResponse для стадии change_view().

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

ModelAdmin.response_delete(request, obj_display, obj_id) [source]

Определяет HttpResponse для стадии delete_view().

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

obj_display — строка с именем удалённого объекта.

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

Параметр obj_id был добавлен.

ModelAdmin.get_changeform_initial_data(request) [source]

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

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

def get_changeform_initial_data(self, request):
    return {'name': 'custom_initial_value'}

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

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

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

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

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

ModelAdmin.changelist_view(request, extra_context=None) [source]

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

ModelAdmin.delete_view(request, object_id, extra_context=None) [source]

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

ModelAdmin.history_view(request, object_id, extra_context=None) [source]

Представление Django для страницы, отображающей историю изменений данного экземпляра модели.

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

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

class MyModelAdmin(admin.ModelAdmin):

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

    def get_osm_info(self):
        # ...
        pass

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

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

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

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

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

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

jQuery

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

Чтобы избежать конфликтов с пользовательскими скриптами или библиотеками, jQuery Django (версия 2.1.4) имеет пространство имён django.jQuery. Если вы хотите использовать jQuery в собственном JavaScript админки без включения второй копии, можете использовать объект django.jQuery в представлениях списка изменений и добавления/редактирования.

Встроенная библиотека jQuery была обновлена с 1.9.1 до 1.11.2.

Встроенная библиотека jQuery была обновлена с 1.11.2 до 2.1.4. Это означает потерю поддержки Internet Explorer 8 и ниже. Вы можете восстановить поддержку, включив собственную версию jQuery 1.X.

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

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

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

Добавление кастомной валидации в админку

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

class ArticleAdmin(admin.ModelAdmin):
    form = MyArticleAdminForm

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

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

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

InlineModelAdmin объекты

class InlineModelAdmin
class TabularInline [source]
class StackedInline [source]

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

from django.db import models

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

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

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

from django.contrib import admin

class BookInline(admin.TabularInline):
    model = Book

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

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

  • TabularInline
  • StackedInline

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

InlineModelAdmin опции

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

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

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

InlineModelAdmin.model

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

InlineModelAdmin.fk_name

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

InlineModelAdmin.formset

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

InlineModelAdmin.form

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

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

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

InlineModelAdmin.extra

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

Для пользователей с браузерами, поддерживающими JavaScript, предоставляется ссылка «Добавить ещё», которая позволяет добавлять любое количество дополнительных строк помимо тех, которые были предоставлены в результате аргумента extra.

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

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

InlineModelAdmin.max_num

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

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

InlineModelAdmin.min_num

Это управляет минимальным количеством форм для отображения в строке. Для получения дополнительной информации см. modelformset_factory().

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

InlineModelAdmin.raw_id_fields

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

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

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

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

InlineModelAdmin.verbose_name

Переопределение поля verbose_name, найденного в внутреннем классе Meta модели.

InlineModelAdmin.verbose_name_plural

Переопределение поля verbose_name_plural, найденного во внутреннем классе Meta модели.

InlineModelAdmin.can_delete

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

InlineModelAdmin.show_change_link

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

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

Возвращает класс BaseInlineFormSet для использования в админ-видах добавления/изменения. См. пример для 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.parent:
            return max_num - 5
        return max_num
InlineModelAdmin.get_min_num(request, obj=None, **kwargs)

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

Переопределите этот метод для программатического определения минимального количества форм строки. Например, это может зависеть от экземпляра модели (переданного в качестве ключевого аргумента obj).

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

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

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 при определении поля многие-ко-многим.

Во-вторых, необходимо вручную исключить поле 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.db import models
from django.contrib.contenttypes.fields import GenericForeignKey

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

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

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

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

from myproject.myapp.models import Image, Product

class ImageInline(GenericTabularInline):
    model = Image

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

admin.site.register(Product, ProductAdmin)

См. документацию по contenttypes для более подробной информации.

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

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

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

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

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

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

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

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

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

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

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

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

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

И это все! Если мы поместили этот файл в каталог templates/admin/my_app, наша ссылка появится в форме изменения для всех моделей в рамках приложения my_app.

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

Не каждый шаблон в contrib/admin/templates/admin можно переопределить по приложению или по модели. Можно переопределить следующие:

  • app_index.html
  • change_form.html
  • change_list.html
  • delete_confirmation.html
  • object_history.html

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

Примечание

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

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

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

AdminSite объекты

class AdminSite(name='admin') [source]

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

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

AdminSite атрибуты

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

AdminSite.site_header

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

AdminSite.site_title

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

AdminSite.site_url

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

AdminSite.index_title

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

AdminSite.index_template

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

AdminSite.app_index_template

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

AdminSite.empty_value_display

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

AdminSite.login_template

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

AdminSite.login_form

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

AdminSite.logout_template

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

AdminSite.password_change_template

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

AdminSite.password_change_done_template

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

AdminSite методы

AdminSite.each_context(request) [source]

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

По умолчанию включает следующие переменные и значения:

  • site_header: AdminSite.site_header
  • site_title: AdminSite.site_title
  • site_url: AdminSite.site_url
  • has_permission: AdminSite.has_permission()
  • available_apps: список приложений из реестра приложений, доступных текущему пользователю. Каждый элемент списка — словарь, представляющий приложение со следующими ключами:

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

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

    • object_name: имя класса модели
    • name: множественное число имени модели
    • perms: отслеживание dict, add, и change разрешений
    • admin_url: URL админского списка изменений для модели
    • add_url: админский URL для добавления новой записи модели

Были добавлены аргумент request и переменная has_permission.

Была добавлена переменная available_apps.

AdminSite.has_permission(request) [source]

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

Подключение экземпляров AdminSite в ваш URLconf

Последний шаг настройки Django админки — подключение вашего экземпляра AdminSite в ваш URLconf. Для этого укажите данный URL на метод AdminSite.urls. Использование include() не обязательно.

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

# urls.py
from django.conf.urls import url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

В предыдущих версиях вы передавали admin.site.urls в include().

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

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

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)
from django.conf.urls import url

from myapp.admin import admin_site

urlpatterns = [
    url(r'^myadmin/', admin_site.urls),
]

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

Несколько админских панелей в одном URLconf

Легко создать несколько экземпляров админской панели на одном сайте Django. Просто создайте несколько экземпляров AdminSite и укажите каждый из них по разному URL.

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

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

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

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

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

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

Примечание

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

В предыдущих версиях Django, вам нужно было предоставить аргумент current_app в RequestContext или Context при отображении шаблона.

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

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

from django.contrib.auth import views as auth_views

url(r'^admin/password_reset/$', auth_views.password_reset, name='admin_password_reset'),
url(r'^admin/password_reset/done/$', auth_views.password_reset_done, name='password_reset_done'),
url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$', auth_views.password_reset_confirm, name='password_reset_confirm'),
url(r'^reset/done/$', auth_views.password_reset_complete, 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 LogEntry, ADDITION

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

Подробное описание изменения. В случае редактирования, сообщение содержит список изменённых полей.

LogEntry методы

LogEntry.get_edited_object()

Сокращение, возвращающее ссылку на объект.

Обращение к админским URL

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

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

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

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

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

UserAdmin предоставляет именованный URL:

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

Эти именованные URL зарегистрированы с именным пространством приложения admin, и с именным пространством экземпляра, соответствующим имени экземпляра сайта.

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

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

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

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

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

Дополнительную информацию см. в документации по обращению к именованным URL.

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

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

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

Декоратор staff_member_required

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

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

  • Если пользователь авторизован, является сотрудником (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):
    ...

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

Spec-Zone.ru

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