Как изменить стили админки django

The web framework for perfectionists with deadlines.

Writing your first Django app, part 7¶

This tutorial begins where Tutorial 6 left off. We’re
continuing the web-poll application and will focus on customizing Django’s
automatically-generated admin site that we first explored in Tutorial 2.

Where to get help:

If you’re having trouble going through this tutorial, please head over to
the Getting Help section of the FAQ.

Customize the admin form¶

By registering the Question model with admin.site.register(Question),
Django was able to construct a default form representation. Often, you’ll want
to customize how the admin form looks and works. You’ll do this by telling
Django the options you want when you register the object.

Let’s see how this works by reordering the fields on the edit form. Replace
the admin.site.register(Question) line with:

polls/admin.py

from django.contrib import admin

from .models import Question


class QuestionAdmin(admin.ModelAdmin):
    fields = ['pub_date', 'question_text']

admin.site.register(Question, QuestionAdmin)

You’ll follow this pattern – create a model admin class, then pass it as the
second argument to admin.site.register() – any time you need to change the
admin options for a model.

This particular change above makes the “Publication date” come before the
“Question” field:

Fields have been reordered

This isn’t impressive with only two fields, but for admin forms with dozens
of fields, choosing an intuitive order is an important usability detail.

And speaking of forms with dozens of fields, you might want to split the form
up into fieldsets:

polls/admin.py

from django.contrib import admin

from .models import Question


class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date']}),
    ]

admin.site.register(Question, QuestionAdmin)

The first element of each tuple in
fieldsets is the title of the fieldset.
Here’s what our form looks like now:

Form has fieldsets now

Customize the admin change list¶

Now that the Question admin page is looking good, let’s make some tweaks to the
“change list” page – the one that displays all the questions in the system.

Here’s what it looks like at this point:

Polls change list page

By default, Django displays the str() of each object. But sometimes it’d be
more helpful if we could display individual fields. To do that, use the
list_display admin option, which is a
tuple of field names to display, as columns, on the change list page for the
object:

polls/admin.py

class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question_text', 'pub_date')

For good measure, let’s also include the was_published_recently() method
from Tutorial 2:

polls/admin.py

class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question_text', 'pub_date', 'was_published_recently')

Now the question change list page looks like this:

Polls change list page, updated

You can click on the column headers to sort by those values – except in the
case of the was_published_recently header, because sorting by the output
of an arbitrary method is not supported. Also note that the column header for
was_published_recently is, by default, the name of the method (with
underscores replaced with spaces), and that each line contains the string
representation of the output.

You can improve that by using the display()
decorator on that method (in polls/models.py), as follows:

polls/models.py

from django.contrib import admin

class Question(models.Model):
    # ...
    @admin.display(
        boolean=True,
        ordering='pub_date',
        description='Published recently?',
    )
    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now

For more information on the properties configurable via the decorator, see
list_display.

Edit your polls/admin.py file again and add an improvement to the
Question change list page: filters using the
list_filter. Add the following line to
QuestionAdmin:

list_filter = ['pub_date']

That adds a “Filter” sidebar that lets people filter the change list by the
pub_date field:

Polls change list page, updated

The type of filter displayed depends on the type of field you’re filtering on.
Because pub_date is a DateTimeField, Django
knows to give appropriate filter options: “Any date”, “Today”, “Past 7 days”,
“This month”, “This year”.

This is shaping up well. Let’s add some search capability:

search_fields = ['question_text']

That adds a search box at the top of the change list. When somebody enters
search terms, Django will search the question_text field. You can use as many
fields as you’d like – although because it uses a LIKE query behind the
scenes, limiting the number of search fields to a reasonable number will make
it easier for your database to do the search.

Now’s also a good time to note that change lists give you free pagination. The
default is to display 100 items per page. Change list pagination, search boxes, filters, date-hierarchies, and
column-header-ordering
all work together like you think they should.

Customize the admin look and feel¶

Clearly, having “Django administration” at the top of each admin page is
ridiculous. It’s just placeholder text.

You can change it, though, using Django’s template system. The Django admin is
powered by Django itself, and its interfaces use Django’s own template system.

Customizing your project’s templates¶

Create a templates directory in your project directory (the one that
contains manage.py). Templates can live anywhere on your filesystem that
Django can access. (Django runs as whatever user your server runs.) However,
keeping your templates within the project is a good convention to follow.

Open your settings file (mysite/settings.py, remember) and add a
DIRS option in the TEMPLATES setting:

mysite/settings.py

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

DIRS is a list of filesystem directories to check
when loading Django templates; it’s a search path.

Organizing templates

Just like the static files, we could have all our templates together, in
one big templates directory, and it would work perfectly well. However,
templates that belong to a particular application should be placed in that
application’s template directory (e.g. polls/templates) rather than the
project’s (templates). We’ll discuss in more detail in the
reusable apps tutorial why we do this.

Now create a directory called admin inside templates, and copy the
template admin/base_site.html from within the default Django admin
template directory in the source code of Django itself
(django/contrib/admin/templates) into that directory.

Where are the Django source files?

If you have difficulty finding where the Django source files are located
on your system, run the following command:

/

$ python -c "import django; print(django.__path__)"
...> py -c "import django; print(django.__path__)"

Then, edit the file and replace
{{ site_header|default:_('Django administration') }} (including the curly
braces) with your own site’s name as you see fit. You should end up with
a section of code like:

{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
{% endblock %}

We use this approach to teach you how to override templates. In an actual
project, you would probably use
the django.contrib.admin.AdminSite.site_header attribute to more easily
make this particular customization.

This template file contains lots of text like {% block branding %}
and {{ title }}. The {% and {{ tags are part of Django’s
template language. When Django renders admin/base_site.html, this
template language will be evaluated to produce the final HTML page, just like
we saw in Tutorial 3.

Note that any of Django’s default admin templates can be overridden. To
override a template, do the same thing you did with base_site.html – copy
it from the default directory into your custom directory, and make changes.

Customizing your application’s templates¶

Astute readers will ask: But if DIRS was empty by
default, how was Django finding the default admin templates? The answer is
that, since APP_DIRS is set to True,
Django automatically looks for a templates/ subdirectory within each
application package, for use as a fallback (don’t forget that
django.contrib.admin is an application).

Our poll application is not very complex and doesn’t need custom admin
templates. But if it grew more sophisticated and required modification of
Django’s standard admin templates for some of its functionality, it would be
more sensible to modify the application’s templates, rather than those in the
project. That way, you could include the polls application in any new project
and be assured that it would find the custom templates it needed.

See the template loading documentation for more
information about how Django finds its templates.

Customize the admin index page¶

On a similar note, you might want to customize the look and feel of the Django
admin index page.

By default, it displays all the apps in INSTALLED_APPS that have been
registered with the admin application, in alphabetical order. You may want to
make significant changes to the layout. After all, the index is probably the
most important page of the admin, and it should be easy to use.

The template to customize is admin/index.html. (Do the same as with
admin/base_site.html in the previous section – copy it from the default
directory to your custom template directory). Edit the file, and you’ll see it
uses a template variable called app_list. That variable contains every
installed Django app. Instead of using that, you can hard-code links to
object-specific admin pages in whatever way you think is best.

Содержание

  • Предварительные условия
  • Настройка Django Admin
  • Кастомизация Django Admin
  • Изменение Change List с помощью list_display
  • Добавление ссылок на страницы других объектов
  • Добавление фильтров
  • Добавление поиска
  • Изменение способа редактирования моделей
  • Переопределение шаблонов Django Admin
  • Заключение

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

В этом руководстве вы узнаете, как:

  • Добавить столбцы атрибутов в список объектов модели.
  • Добавить ссылки на страницы других объектов.
  • Добавить фильтры в список объектов модели.
  • Добавить поиск в список объектов модели.
  • Изменить форму редактирования объекта.
  • Переопределить шаблоны Django admin.

Предварительные условия

Чтобы получить максимум от этого руководства, вы должны быть знакомы с Django, особенно с моделями. Поскольку Django не является частью стандартной библиотеки Python, то вы также должны быть знакомы с pip и pyenv (или аналогичным инструментом виртуального окружения). Чтобы узнать больше об этих темах, можете ознакомиться со следующими ресурсами:

  • Get Started With Django Part 1: Build a Portfolio App
  • What is Pip? A Guide for New Pythonistas
  • Managing Multiple Python Versions With pyenv
  • What Virtual Environments Are Good For

Фрагменты кода в этом руководстве были протестированы на Django 3.0.7. Они должны работать в любой версии, которую вы используете, но могут быть незначительные различия.


Настройка Django Admin

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

$ python -m pip install django
$ django-admin startproject School
$ cd School
$ ./manage.py startapp core
$ ./manage.py migrate
$ ./manage.py createsuperuser
Username: admin
Email address: admin@example.com
Password:
Password (again):

Сначала создайте новый проект Django под названием School с приложением под названием core. Затем выполните команду migrate и создайте администратора. Доступ к админ-панели  Django разрешен только пользователям с флагами staff или superuser, поэтому для создания суперпользователя используется команда createsuperuser.

Вам также необходимо внести изменения в файл School/settings.py, чтобы включить новое приложение с именем core:

# School/settings.py
# ...

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "core",    # Add this line
]

Каталог приложения core будет содержать следующие файлы:

core/
│
├── migrations/
│   └── __init__.py
│
├── __init__.py
├── admin.py
├── apps.py
├── models.py
├── tests.py
└── views.py

Из этих файлов нас интересуют два:

  1. models.py, в котором определяются модели.
  2. admin.py,  в котором модели регистрируются в Django admin.

Чтобы продемонстрировать кастомизацию Django admin, вам понадобятся несколько моделей. Отредактируйте core/models.py следующим образом:

from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models

class Person(models.Model):
    last_name = models.TextField()
    first_name = models.TextField()
    courses = models.ManyToManyField("Course", blank=True)

    class Meta:
        verbose_name_plural = "People"

class Course(models.Model):
    name = models.TextField()
    year = models.IntegerField()

    class Meta:
        unique_together = ("name", "year", )

class Grade(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    grade = models.PositiveSmallIntegerField(
        validators=[MinValueValidator(0), MaxValueValidator(100)])
    course = models.ForeignKey(Course, on_delete=models.CASCADE)

Эти модели представляют учащихся, проходящих курсы в школе. У модели Course есть два поля: название курса и год, в котором он был начат. Модель Person имеет три поля: имя и фамилия учащегося и курсы, которые он проходит (ноль или более). Grade содержит оценку, полученную учащимся (Person) на курсе (Course).

Вот диаграмма, показывающая отношения между объектами:

Имена таблиц в базе данных немного отличаются от этих, но они связаны с моделями, показанными выше.

Каждую модель, которую вы хотите отображать в админ-панели Django, необходимо зарегистрировать. Делается это в файле admin.py. Модели из core/models.py регистрируются в соответствующем файле core/admin.py:

from django.contrib import admin

from core.models import Person, Course, Grade

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    pass

@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
    pass

@admin.register(Grade)
class GradeAdmin(admin.ModelAdmin):
    pass

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

$ ./manage.py makemigrations
$ ./manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, core, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  ...
  Applying core.0001_initial... OK
  Applying core.0002_auto_20200609_2120... OK
  Applying sessions.0001_initial... OK
$ ./manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
Django version 3.0.7, using settings 'School.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Теперь перейдите по адресу http://127.0.0.1:8000/admin, чтобы увидеть интерфейс администратора. Вам будет предложено войти в систему. Используйте учетные данные, созданные с помощью команды createsuperuser.

На главной странице Django admin перечислены все зарегистрированные модели:

django admin

Теперь вы можете использовать админ-панель для создания объектов в своей базе данных. Щелкнув по названию модели, вы увидите список всех объектов в базе данных для этой модели. Вот, например, список людей (Person):

django admin

Сначала список пустой, как и ваша база данных. Нажав ADD PERSON, вы можете создать человека в базе данных. После сохранения вы вернетесь к списку объектов Person:

django admin

Хорошая новость в том, что у вас есть объект. Плохая новость в том, что Person object (1) сообщает вам id объекта и ничего больше. По умолчанию, Django admin отображает каждый объект, вызывая функцию str(). Вы можете сделать эту страницу более полезной, добавив метод .__str__() в класс Person в core/models.py:

class Person(models.Model):
    last_name = models.TextField()
    first_name = models.TextField()
    courses = models.ManyToManyField("Course", blank=True)

    def __str__(self):
        return f"{self.last_name}, {self.first_name}"

Добавление метода Person.__str__() изменяет отображение: теперь вместо id отображаются имя и фамилия человека. Вы можете обновить страницу, чтобы увидеть изменения:

django admin

Так-то лучше! Теперь вы можете увидеть некоторую информацию об объекте Person. Рекомендуется добавить подобные методы как к объектам Course, так и к объектам Grade:

class Course(models.Model):
    # ...

    def __str__(self):
        return f"{self.name}, {self.year}"

class Grade(models.Model):
    # ...

    def __str__(self):
        return f"{self.grade}, {self.person}, {self.course}"

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

Django позволяет загружать данные в базу данных и выгружать из нее с помощью файлов, называемых фикстурами. Скопируйте следующее в файл с именем core/fixtures/school.json:

[
    {
        "model": "core.person",
        "pk": 1,
        "fields": {
            "last_name": "Harris",
            "first_name": "Xander",
            "courses": [
                1,
                3
            ]
        }
    },
    {
        "model": "core.person",
        "pk": 3,
        "fields": {
            "last_name": "Rosenberg",
            "first_name": "Willow",
            "courses": [
                1,
                2,
                3
            ]
        }
    },
    {
        "model": "core.person",
        "pk": 16,
        "fields": {
            "last_name": "Summers",
            "first_name": "Buffy",
            "courses": [
                1,
                2,
                3
            ]
        }
    },
    {
        "model": "core.course",
        "pk": 1,
        "fields": {
            "name": "CompSci G11",
            "year": 1998
        }
    },
    {
        "model": "core.course",
        "pk": 2,
        "fields": {
            "name": "Psych 101",
            "year": 1999
        }
    },
    {
        "model": "core.course",
        "pk": 3,
        "fields": {
            "name": "Library Science G10",
            "year": 1997
        }
    },
    {
        "model": "core.grade",
        "pk": 1,
        "fields": {
            "person": 16,
            "grade": 68,
            "course": 1
        }
    },
    {
        "model": "core.grade",
        "pk": 2,
        "fields": {
            "person": 16,
            "grade": 87,
            "course": 2
        }
    },
    {
        "model": "core.grade",
        "pk": 3,
        "fields": {
            "person": 16,
            "grade": 76,
            "course": 3
        }
    },
    {
        "model": "core.grade",
        "pk": 4,
        "fields": {
            "person": 1,
            "grade": 58,
            "course": 1
        }
    },
    {
        "model": "core.grade",
        "pk": 5,
        "fields": {
            "person": 1,
            "grade": 58,
            "course": 3
        }
    },
    {
        "model": "core.grade",
        "pk": 6,
        "fields": {
            "person": 3,
            "grade": 98,
            "course": 3
        }
    },
    {
        "model": "core.grade",
        "pk": 7,
        "fields": {
            "person": 3,
            "grade": 97,
            "course": 2
        }
    }
]

Создав файл, вы можете использовать команду loaddata, чтобы загрузить его в свою базу данных:

$ ./manage.py loaddata school
Installed 13 object(s) from 1 fixture(s)

Теперь в вашей базе данных есть несколько объектов Person, Course и Grade.

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


Кастомизация Django Admin

Умные люди, создавшие фреймворк Django, не только создали админку, но и сделали это таким образом, чтобы вы могли кастомизировать ее для своих проектов. Когда вы ранее регистрировали объект PersonAdmin, он наследовался от admin.ModelAdmin. Большая часть настроек, которые вы можете сделать с помощью Django admin, выполняется путем модификации класса ModelAdmin, и вы, конечно, можете изменять его!

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

В довершение ко всему, админка построена с использованием шаблонов Django. Механизм шаблонов Django позволяет вам переопределять существующие шаблоны, а поскольку Django admin — это просто еще один набор шаблонов, это означает, что вы можете полностью изменить его HTML-код.

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

Django admin разделен на три основные области:

  1. App index
  2. Change lists
  3. Change forms

В app index перечислены ваши зарегистрированные модели. Change list автоматически создается для каждой зарегистрированной модели и содержит список объектов для этой модели. Когда вы добавляете или редактируете один из этих объектов, вы делаете это с помощью change form.

В предыдущем примере app index отображал объекты Person, Course и Grade. При нажатии на People отображаются change list’ы для объектов Person. На странице change list, щелкнув по объекту Buffy Summers, вы попадете на страницу change form, чтобы отредактировать данные о Buffy Summers.


Изменение Change List с помощью list_display

Реализация метода .__str__() — это быстрый способ изменить представление объекта Person с бессмысленной строки на понятные данные. Поскольку это представление также будет отображаться в раскрывающихся списках со множественным выбором, вы определенно захотите сделать его максимально простым и понятным.

Вы можете кастомизировать страницу change list гораздо большим количеством способов, чем просто изменить строковое представление объекта. Атрибут list_display объекта admin.ModelAdmin указывает, какие столбцы будут отображаться в change list’e. Это значение представляет собой кортеж атрибутов моделируемого объекта. Например, в core/admin.py измените PersonAdmin следующим образом:

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    list_display = ("last_name", "first_name")

Приведенный выше код модифицирует ваш Person change list таким образом, что теперь будут отображаться атрибуты last_name и first_name для каждого объекта Person. Каждый атрибут отображается в столбце на странице:

Эти два столбца кликабельны, что позволяет сортировать страницу по данным столбца. Django admin также учитывает атрибут ordering в Meta-классе:

class Person(models.Model):
    # ...

    class Meta:
        ordering = ("last_name", "first_name")

    # ...

Добавление атрибута ordering приведет к тому, что по умолчанию все запросы к Person будут упорядочены по last_name, а затем по first_name. Django будет соблюдать этот порядок по умолчанию как в админке, так и при получении объектов.

Кортеж list_display может ссылаться на любой атрибут объекта. Он также может ссылаться на метод в самом admin.ModelAdmin. Снова изменим PersonAdmin:

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    list_display = ("last_name", "first_name", "show_average")

    def show_average(self, obj):
        from django.db.models import Avg
        result = Grade.objects.filter(person=obj).aggregate(Avg("grade"))
        return result["grade__avg"]

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

Параметр obj — это объект для отображаемой строки. В этом случае вы используете его для запроса соответствующих объектов Grade для учащегося, затем получаете среднее значение Grade.grade. Вы можете увидеть результаты здесь:

Имейте в виду, что средний бал на самом деле нужно рассчитывать в объекте модели Person. Скорее всего, вам понадобятся данные, находящиеся где-нибудь еще, а не только в Django admin. Если бы у вас был такой метод, вы могли бы добавить его в атрибут list_display. Приведенный пример показывает, что вы можете делать в объекте ModelAdmin, но, вероятно, это не лучший выбор для вашего кода.

По умолчанию сортируются только те столбцы, которые являются атрибутами объекта. show_average() — нет. Это связано с тем, что сортировка выполняется с помощью QuerySet. В некоторых случаях есть способы сортировки этих столбцов, но это выходит за рамки нашего руководства.

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

def show_average(self, obj):
    result = Grade.objects.filter(person=obj).aggregate(Avg("grade"))
    return result["grade__avg"]

show_average.short_description = "Average Grade"

По умолчанию Django защищает вас от HTML в строках, если строка является результатом пользовательского ввода.  Чтобы отображение включало HTML, вы должны использовать format_html():

def show_average(self, obj):
    from django.utils.html import format_html

    result = Grade.objects.filter(person=obj).aggregate(Avg("grade"))
    return format_html("<b><i>{}</i></b>", result["grade__avg"])

show_average.short_description = "Average"

Теперь столбец show_average() имеет кастомное название «Average» и выделен курсивом:

К сожалению, в Django еще не добавлена поддержка f-строк для format_html(), поэтому используется синтаксис str.format().


Добавление ссылок на страницы других объектов

Объекты довольно часто ссылаются на другие объекты с помощью внешних ключей (foreign key). Вы можете указать в list_display метод, возвращающий ссылку HTML. Внутри core/admin.py измените класс CourseAdmin следующим образом:

from django.urls import reverse
from django.utils.http import urlencode

@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
    list_display = ("name", "year", "view_students_link")

    def view_students_link(self, obj):
        count = obj.person_set.count()
        url = (
            reverse("admin:core_person_changelist")
            + "?"
            + urlencode({"courses__id": f"{obj.id}"})
        )
        return format_html('<a href="{}">{} Students</a>', url, count)

    view_students_link.short_description = "Students"

Теперь Course change list состоит из трех столбцов:

  1. название курса.
  2. год, в котором был начат курс.
  3. ссылка, отображающая количество учащихся, проходящих курс.

Вы можете увидеть результат на следующем скриншоте:

Когда вы нажимаете по ссылке 2 Students, вы попадаете на страницу Person change list с примененным фильтром. На отфильтрованной странице показаны только ученики из Psych 101: Buffy и Willow. Xander не поступил в университет.

В примере кода для поиска URL-адреса в админке используется функция reverse(). Вы можете найти любую страницу Django admin, используя следующее соглашение об именах:

"admin:%(app)s_%(model)s_%(page)"

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

  • admin: — это пространство имен.
  • app — это название приложения.
  • model — это объект модели.
  • page — это тип страницы Django admin.

В приведенном выше примере view_students_link() вы используете admin:core_person_changelist, чтобы получить ссылку на страницу change list объекта Person в приложении core.

Вот доступные URL-адреса:

Страница

URL

Цель

Change list

%(app)s_%(model)s_changelist

Список страниц объектов модели

Add

%(app)s_%(model)s_add

Страница создания объекта

History

%(app)s_%(model)s_history

Страница истории изменений объекта

Принимает object_id в качестве параметра

Delete

%(app)s_%(model)s_delete

Страница удаления объекта

Принимает object_id в качестве параметра

Change

%(app)s_%(model)s_change

Страница редактирования объекта

Принимает object_id в качестве параметра

Вы можете отфильтровать страницу change list, добавив к URL-адресу строку запроса. Эта строка запроса изменяет QuerySet, используемый для заполнения страницы. В приведенном выше примере строка запроса "?courses__id={obj.id}" фильтрует список Person по id курса (отображаются только те объекты, которые имеют соответствующее значение Person.course).

Эти фильтры поддерживают поиск полей QuerySet с использованием двойного подчеркивания (__). Вы можете получить доступ к атрибутам связанных объектов, а также использовать модификаторы фильтра, такие как __exact и __startswith.

Полную информацию о том, чего вы можете достичь с помощью атрибута list_display, вы можете найти в документации Django admin.


Добавление фильтров

Помимо фильтрации данных в change list через URL-адрес, вы также можете фильтровать с помощью встроенного виджета. Добавьте атрибут list_filter к объекту CourseAdmin в core/admin.py:

@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
    list_display = ("name", "year", "view_students_link")
    list_filter = ("year", )
# ...

list_filter отобразит новый раздел на странице со списком ссылок. В этом случае ссылки фильтруют страницу по годам. Список фильтров автоматически заполняется значениями лет, используемыми объектами Course в базе данных:

Если щелкнуть по году справа, в список будут включены только объекты курса с этим значением года. Вы также можете фильтровать по атрибутам связанных объектов, используя синтаксис поиска поля __. Например, вы можете отфильтровать объекты GradeAdmin по course__year, показывая объекты Grade только для курсов определенного года.

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


Добавление поиска

Фильтры — не единственный способ уменьшить объем данных на экране. Django admin также поддерживает поиск с помощью опции search_fields, которая добавляет на экран поле поиска. Вы устанавливаете его с помощью кортежа, содержащего имена полей, которые будут использоваться для построения поискового запроса в базе данных.

Все, что пользователь вводит в поле поиска, используется в условии OR полей, фильтрующих QuerySet. По умолчанию каждый параметр поиска окружен знаками %. То есть, если вы ищете r, то в результатах появится любое слово с r внутри. Вы можете быть более точными, указав модификатор __ в поле поиска.

Отредактируйте PersonAdmin в core/admin.py следующим образом:

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    search_fields = ("last_name__startswith", )

В приведенном выше коде поиск основан на фамилии. Модификатор __startswith ограничивает поиск фамилиями, которые начинаются с параметра поиска. Поиск по R дает следующие результаты:

Каждый раз, когда выполняется поиск на странице change list, Django admin вызывает метод get_search_results() вашего объекта admin.ModelAdmin. Он возвращает QuerySet с результатами поиска. Вы можете точно настроить поиск, перегрузив метод и изменив QuerySet. Более подробную информацию можно найти в документации.


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

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

Вы можете контролировать, какие поля включены, а также их порядок. Измените свой объект PersonAdmin, добавив атрибут fields:

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    fields = ("first_name", "last_name", "courses")
# ...

Страницы добавления и изменения для Person теперь помещают атрибут first_name перед атрибутом last_name, хотя сама модель указывает обратное:

ModelAdmin.get_form() отвечает за создание ModelForm для вашего объекта. Вы можете переопределить этот метод, чтобы изменить форму. Добавьте в PersonAdmin следующий метод:

def get_form(self, request, obj=None, **kwargs):
    form = super().get_form(request, obj, **kwargs)
    form.base_fields["first_name"].label = "First Name (Humans only!):"
    return form

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

Изменения метки может быть недостаточно, чтобы помешать вампирам зарегистрироваться в качестве студентов. Если вам не нравится ModelForm, созданная для вас Django admin, вы можете использовать атрибут form для регистрации пользовательской формы. Внесите следующие дополнения и изменения в core/admin.py:

from django import forms

class PersonAdminForm(forms.ModelForm):
    class Meta:
        model = Person
        fields = "__all__"

    def clean_first_name(self):
        if self.cleaned_data["first_name"] == "Spike":
            raise forms.ValidationError("No Vampires")

        return self.cleaned_data["first_name"]

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    form = PersonAdminForm
# ...

Приведенный выше код обеспечивает дополнительную проверку на страницах добавления и изменения человека (Person). Объекты ModelForm имеют богатый механизм проверки. В этом случае поле first_name проверяется на соответствие имени «Spike». ValidationError не позволяет студентам с этим именем зарегистрироваться:

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


Переопределение шаблонов Django Admin

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

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

.../site-packages/django/contrib/admin/templates/
│
├── admin/
│   │
│   ├── auth/
│   │   └── user/
│   │       ├── add_form.html
│   │       └── change_password.html
│   │
│   ├── edit_inline/
│   │   ├── stacked.html
│   │   └── tabular.html
│   │
│   ├── includes/
│   │   ├── fieldset.html
│   │   └── object_delete_summary.html
│   │
│   ├── widgets/
│   │   ├── clearable_file_input.html
│   │   ├── foreign_key_raw_id.html
│   │   ├── many_to_many_raw_id.html
│   │   ├── radio.html
│   │   ├── related_widget_wrapper.html
│   │   ├── split_datetime.html
│   │   └── url.html
│   │
│   ├── 404.html
│   ├── 500.html
│   ├── actions.html
│   ├── app_index.html
│   ├── base.html
│   ├── base_site.html
│   ├── change_form.html
│   ├── change_form_object_tools.html
│   ├── change_list.html
│   ├── change_list_object_tools.html
│   ├── change_list_results.html
│   ├── date_hierarchy.html
│   ├── delete_confirmation.html
│   ├── delete_selected_confirmation.html
│   ├── filter.html
│   ├── index.html
│   ├── invalid_setup.html
│   ├── login.html
│   ├── object_history.html
│   ├── pagination.html
│   ├── popup_response.html
│   ├── prepopulated_fields_js.html
│   ├── search_form.html
│   └── submit_line.html
│
└── registration/
    ├── logged_out.html
    ├── password_change_done.html
    ├── password_change_form.html
    ├── password_reset_complete.html
    ├── password_reset_confirm.html
    ├── password_reset_done.html
    ├── password_reset_email.html
    └── password_reset_form.html

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

Шаблоны Django admin находятся в двух каталогах:

  1. admin — предназначен для страниц объекта модели.
  2. registration — предназначен для смены пароля, входа и выхода.

Чтобы кастомизировать страницу выхода, вам необходимо переопределить правильный файл. Относительный путь, ведущий к файлу, должен совпадать с тем, который был переопределен. Нас интересует файл registration/logged_out.html. Начнем с создания каталога в проекте School:

$ mkdir -p templates/registration

Теперь сообщите Django о вашем новом каталоге шаблонов в файле School/settings.py. Найдите TEMPLATES и добавьте папку в список DIR:

# School/settings.py
# ...

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",

        # Добавление папки
        "DIRS": [os.path.join(BASE_DIR, "templates"), ],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]

Шаблонизатор ищет каталоги в параметре DIR перед каталогами приложений, поэтому вместо этого будет загружено все, что имеет то же имя, что и шаблон админ-панели. Чтобы увидеть это в действии, скопируйте файл logged_out.html в каталог templates/registration, затем измените его:

{% extends "admin/base_site.html" %}
{% load i18n %}

{% block breadcrumbs %}<div class="breadcrumbs"><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></div>{% endblock %}

{% block content %}

<p>You are now leaving Sunnydale</p>

<p><a href="{% url 'admin:index' %}">{% trans 'Log in again' %}</a></p>

{% endblock %}

Вы кастомизировали страницу выхода. Если вы нажмете LOG OUT, то увидите кастомное сообщение:

Шаблоны Django admin отличаются глубокой вложенностью и не очень интуитивно понятны, но вы можете полностью контролировать их представление, если вам это нужно. Некоторые пакеты, включая Grappelli и Django Admin Bootstrap, полностью заменили шаблоны Django admin, изменив их внешний вид.

Django Admin Bootstrap еще не совместим с Django 3, а Grappelli только недавно добавил поддержку, так что у него все еще могут быть некоторые проблемы. Но если вы хотите увидеть силу переопределения шаблонов админки, ознакомьтесь с этими проектами!


Заключение

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

В этом руководстве вы узнали, как:

  • Зарегистрировать свои модели в Django admin.
  • Добавить атрибуты в виде столбцов в change list.
  • Создать значения столбцов с вычисляемым содержимым.
  • Сделать перекрестные ссылки на страницы админки.
  • Фильтровать страницы change list.
  • Добавлять поиск на страницы change list.
  • Кастомизировать объект ModelForm.
  • Изменять HTML в шаблонах Django admin.

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

Архив проекта: lesson-24-coolsite.zip

На этом занятии
мы сделаем некоторые изменения в админ-панели, настроим ее под свой
разрабатываемый сайт. Если перейти в документацию по Django, то на
официальной странице:

https://docs.djangoproject.com/en/3.1/

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

Меняем стили оформления

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

  • admin/index.html

    D:\Python\django\djsite\venv\lib\site-packages\django\contrib\admin\templates\admin\index.html

  • admin/base_site.html

    D:\Python\django\djsite\venv\lib\site-packages\django\contrib\admin\templates\admin\base_site.html

  • admin/base.html

    D:\Python\django\djsite\venv\lib\site-packages\django\contrib\admin\templates\admin\base.html

  • admin/app_list.html

    D:\Python\django\djsite\venv\lib\site-packages\django\contrib\admin\templates\admin\app_list.html

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

Давайте, откроем
его и по идее, конечно, можно было бы внести изменения прямо здесь. Но это не
лучшая практика. Все дополнительные файлы, которые были сформированы при
установке Django, лучше
оставлять без изменений. А переопределение делать уже непосредственно в нашем
проекте. В частности, если добавить в каталог coolsite/templates подкаталог admin и там
разместить файл с тем же именем base_site.html, то Django, сканируя
первым этот каталог, найдет первым файл admin/base_site.html и именно его
будет использовать.

Создадим такой
файл. Перейдем в браузер, обновим страницу админ-панели и не увидим никаких
изменений. Мало того, если посмотреть в Debug Toolbar, то путь к
шаблону base_site.html остался прежним.
Что не так? Дело в том, что Django по умолчанию ищет шаблоны
исключительно в папках приложений. У нас же каталог templates находится
непосредственно в корне проекта, что необходимо, чтобы произошло
переопределение шаблона base_site.html. Этот новый,
нестандартный путь следует указать в файле конфигурации settings.py в коллекции TEMPLATES:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
...
    },
]

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

В файле base_site.html видим три
блока:

  • block title – отвечает за
    отображение заголовка во вкладке;

  • block branding – за
    отображение ссылки «Администрирование Django» в верхней панели;

  • block nav-global
    – глобальный блок навигации.

Сейчас мы хотим
прописать свои собственные стили оформления. Как это сделать? Для этого откроем
шаблон более верхнего уровня base.html и видим
специальный блок:

{% block
extrastyle %}{% endblock %}

который служит
для добавления дополнительных стилей оформления. Пропишем его в файле base_site.html и в нем укажем
свой файл оформления:

{% block extrastyle %}
<link rel="stylesheet" href="{% static 'css/admin.css' %}">
{% endblock %}

Соответственно,
выше загрузим тег static:

и сформируем
файл admin.css в нашем
приложении в каталоге static/css:

#header {
    background: #5e3a00;
}

Почему мы
прописали именно такой селектор для изменения цвета верхней панели? Очень
просто. Если перейти в браузер и проинспектировать этот элемент, то увидим тег div с id=»header». Значит,
для назначения свойств, можно использовать этот идентификатор. По аналогии
можно переобозначать стили для всех других элементов админ-панели. Например,
такой же стиль пропишем и для заголовков блоков:

#header, .module caption {
    background: #5e3a00;
}

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

Если же вам
нужно изменить сам заголовок «Администрирование Django», то это лучше
делать через модуль admin (файл women/admin.py), в котором,
следует определить два таких атрибута:

admin.site.site_title = 'Админ-панель сайта о женщинах'
admin.site.site_header = 'Админ-панель сайта о женщинах'

Полный список
подобных атрибутов можно посмотреть на странице документации:

https://docs.djangoproject.com/en/3.1/ref/contrib/admin/

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

Следующим шагом
добавим отображение миниатюр изображений, связанных с нашими постами,
непосредственно в списке. Сейчас у нас происходит отображение пути к
изображению в колонке «Фото». Мы же хотим показывать непосредственно
изображение, а не путь. Как это сделать?

Для этого в
классе WomenAdmin (файл women/admin.py) следует
прописать метод, который бы возвращал HTML-код. И этот HTML-фрагмент,
затем, подставим вместо путей. Имя метода мы придумываем сами, например, так:

    def get_html_photo(self, object):
        return mark_safe(f"<img src='{object.photo.url}' width=50>")

Этот метод будет
принимать второй параметр object – ссылку на
текущую запись (на текущий пост) и, затем, возвращаем фрагмент HTML, но помеченный
фильтром safe, чтобы теги
воспринимались как теги и не экранировались, то есть, не заменялись бы
спецсимволами. Именно для этого и используется функция mark_safe(). Все, если
теперь вместо поля photo (в списке list_display) указать метод get_html_photo:

list_display = ('id', 'title', 'time_create', 'get_html_photo', 'is_published')

должны увидеть
вместо маршрутов картинки, связанные с постами. Однако, у нас отображается
ошибка с исключением ValueError, так как не все посты имеют
изображения. Поэтому в методе get_html_photo следует
прописать проверку:

    def get_html_photo(self, object):
        if object.photo:
            return mark_safe(f"<img src='{object.photo.url}' width=50>")

Причем, по else можно ничего не
возвращать (будет формироваться значение None), тогда Django автоматически
поставит дефис там, где фотография отсутствует. Если же прописать иначе:

    def get_html_photo(self, object):
        if object.photo:
            return mark_safe(f"<img src='{object.photo.url}' width=50>")
        else:
            return "Нет фото"

То вместо дефиса
увидим нашу строку «Нет фото». Наконец, чтобы поменять название столбца (вместо
«GET HTML PHOTO»), нужно у объекта-метода get_html_photo определить
специальный атрибут:

get_html_photo.short_description = "Миниатюра"

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

Наконец, мы
можем сделать вывод фотографии и непосредственно на странице редактирования
поста. Для этого, опять же в классе WomenAdmin (файл women/admin.py) пропишем еще
один атрибут:

fields = ('title', 'slug', 'cat', 'content', 'photo', 'is_published')

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

readonly_fields = ('time_create', 'time_update')

И только после
этого, их можно добавить в коллекцию fields:

fields = ('title', 'slug', 'cat', 'content', 'photo', 'is_published', 'time_create', 'time_update')

Отлично, это мы
сделали, но как отобразить миниатюру? Для этого достаточно указать ссылку на
наш метод get_html_photo() в этих
атрибутах:

fields = ('title', 'slug', 'cat', 'content', 'photo', 'get_html_photo', 'is_published', 'time_create', 'time_update')
readonly_fields = ('time_create', 'time_update', 'get_html_photo')

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

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

добавляет верхнюю
панель для управления записью, что бывает очень удобно.

Вот так, можно
настраивать стили и отображение содержимого админ-панели.

Видео по теме

Often the default Django admin page is great and it is all we need for our projects but sometimes we may want to expand what default admin interface can do. We have a lot of tools in Django to customize it to our own needs and in this article, we’ll learn how to customize the admin interface and add multiple features:

Let’s setup your project, add models into models.py and register your models.

models.py

Run following commands – 
 

Python manage.py makemigrations
Python manage.py migrate

Now we have created following models, Here is how they look like in Admin panel – 
 

Default Django admin

Django Admin – Redesign and Customization

Le’s check how we can add multiple features in Django admin panel. Here is a list of customizations – 
 

1. Changing order of Fields

By default, the admin will display fields in the detail view in the same order as defined in the model. But we can change that by making a few edits to the admin.py file without going to models.py and changing the order of different fields.

Movie model:
title
length
release_year
title=['release_year', 'title', 'length']
Movie_Model:
release_year
title
length

admin.py

Python

from django.contrib import admin

from .models import Movie, Customer

class MovieAdmin(admin.ModelAdmin):

    title = ['release_year', 'title', 'length']

admin.site.register(Movie, MovieAdmin)

admin.site.register(Customer)

Changed order of fields

2. Adding Search and Filters

Currently, we have only a few entries in our models, but what if the entries increase to hundreds or thousands due to more number of users? To get data of a particular entry will become tedious if we go by looking at each entry. Therefore we need to add a search bar or a filter feature to allow entries to be accessed easily.

Search by the following elements:
search_fields = ['title', 'length', 'release_year']
search_fields = ['first_name', 'last_name', 'phone']
Filter by the following elements:
list_filter = ['release_year']
list_filter = ['last_name']

app_folder / admin.py

Python

from django.contrib import admin

from .models import Movie, Customer

class MovieAdmin(admin.ModelAdmin):

    search_fields = ['title', 'length', 'release_year']

    list_filter = ['release_year']

class CustomerAdmin(admin.ModelAdmin):

    search_fields = ['first_name', 'last_name', 'phone']

    list_filter = ['last_name']

admin.site.register(Movie, MovieAdmin)

admin.site.register(Customer, CustomerAdmin)

Movies Model showing Filter and Search

Customers Model showing Search and Filter

3. Viewing Additional Fields

In admin interface, normally we see only one field of our models in the list view. We can add more fields to view with list_display.

list_display=['title', 'release_year']
list_display=['first_name', 'last_name', 'phone']

admin.py

Python

from django.contrib import admin

from .models import Movie, Customer

class MovieAdmin(admin.ModelAdmin):

  list_display =['title', 'release_year']

class customerAdmin(admin.ModelAdmin):

  list_display =['first_name', 'last_name', 'phone']

admin.site.register(Movie, MovieAdmin)

admin.site.register(Customer, CustomerAdmin)

title and release year Fields in Movie Model

first name, last name and phone number Fields  in Customer Model

4. Editing List View

You can add the ability to edit attribute values directly from the list view instead of going to the detail view

editable_list = ['phone']

admin.py

Python

from django.contrib import admin

from .models import Movie, Customer

class CustomerAdmin(admin.ModelAdmin):

    editable_list = ['phone']

admin.site.register(Movie)

admin.site.register(Customer, CustomerAdmin)

Phone Number is editable here in Customer Class

5. Admin Template

Sometimes you may want to change the layout and user interface of admin interface for which you need to add your own templates into the project which will then be reflected to your django admin interface.

Create a folder templates in the root folder and inside it, create another folder admin. Now add your html file inside the admin folder.

templates—->admin—->base_site.html

HTML

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

{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}

{% block branding %}

<h1 id="site-name" style="font-family: cursive;" ><a href="{% url 'admin:index' %}">Video Rental Administration</a></h1>

{% endblock %}

{% block nav-global %}{% endblock %}

Heading is changed 

Here, the heading in the admin interface has changed due to the addition of html file. Sometimes template doesn’t get applied to the interface, to avoid that, make sure you’ve done correct template configuration in the settings.py file.

import os

TEMPLATES=[

'DIRS': [os.path.join(BASE_DIR, 'templates')],

]

This how you can customize the admin template in Django as per your requirements.

Often the default Django admin page is great and it is all we need for our projects but sometimes we may want to expand what default admin interface can do. We have a lot of tools in Django to customize it to our own needs and in this article, we’ll learn how to customize the admin interface and add multiple features:

Let’s setup your project, add models into models.py and register your models.

models.py

Run following commands – 
 

Python manage.py makemigrations
Python manage.py migrate

Now we have created following models, Here is how they look like in Admin panel – 
 

Default Django admin

Django Admin – Redesign and Customization

Le’s check how we can add multiple features in Django admin panel. Here is a list of customizations – 
 

1. Changing order of Fields

By default, the admin will display fields in the detail view in the same order as defined in the model. But we can change that by making a few edits to the admin.py file without going to models.py and changing the order of different fields.

Movie model:
title
length
release_year
title=['release_year', 'title', 'length']
Movie_Model:
release_year
title
length

admin.py

Python

from django.contrib import admin

from .models import Movie, Customer

class MovieAdmin(admin.ModelAdmin):

    title = ['release_year', 'title', 'length']

admin.site.register(Movie, MovieAdmin)

admin.site.register(Customer)

Changed order of fields

2. Adding Search and Filters

Currently, we have only a few entries in our models, but what if the entries increase to hundreds or thousands due to more number of users? To get data of a particular entry will become tedious if we go by looking at each entry. Therefore we need to add a search bar or a filter feature to allow entries to be accessed easily.

Search by the following elements:
search_fields = ['title', 'length', 'release_year']
search_fields = ['first_name', 'last_name', 'phone']
Filter by the following elements:
list_filter = ['release_year']
list_filter = ['last_name']

app_folder / admin.py

Python

from django.contrib import admin

from .models import Movie, Customer

class MovieAdmin(admin.ModelAdmin):

    search_fields = ['title', 'length', 'release_year']

    list_filter = ['release_year']

class CustomerAdmin(admin.ModelAdmin):

    search_fields = ['first_name', 'last_name', 'phone']

    list_filter = ['last_name']

admin.site.register(Movie, MovieAdmin)

admin.site.register(Customer, CustomerAdmin)

Movies Model showing Filter and Search

Customers Model showing Search and Filter

3. Viewing Additional Fields

In admin interface, normally we see only one field of our models in the list view. We can add more fields to view with list_display.

list_display=['title', 'release_year']
list_display=['first_name', 'last_name', 'phone']

admin.py

Python

from django.contrib import admin

from .models import Movie, Customer

class MovieAdmin(admin.ModelAdmin):

  list_display =['title', 'release_year']

class customerAdmin(admin.ModelAdmin):

  list_display =['first_name', 'last_name', 'phone']

admin.site.register(Movie, MovieAdmin)

admin.site.register(Customer, CustomerAdmin)

title and release year Fields in Movie Model

first name, last name and phone number Fields  in Customer Model

4. Editing List View

You can add the ability to edit attribute values directly from the list view instead of going to the detail view

editable_list = ['phone']

admin.py

Python

from django.contrib import admin

from .models import Movie, Customer

class CustomerAdmin(admin.ModelAdmin):

    editable_list = ['phone']

admin.site.register(Movie)

admin.site.register(Customer, CustomerAdmin)

Phone Number is editable here in Customer Class

5. Admin Template

Sometimes you may want to change the layout and user interface of admin interface for which you need to add your own templates into the project which will then be reflected to your django admin interface.

Create a folder templates in the root folder and inside it, create another folder admin. Now add your html file inside the admin folder.

templates—->admin—->base_site.html

HTML

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

{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}

{% block branding %}

<h1 id="site-name" style="font-family: cursive;" ><a href="{% url 'admin:index' %}">Video Rental Administration</a></h1>

{% endblock %}

{% block nav-global %}{% endblock %}

Heading is changed 

Here, the heading in the admin interface has changed due to the addition of html file. Sometimes template doesn’t get applied to the interface, to avoid that, make sure you’ve done correct template configuration in the settings.py file.

import os

TEMPLATES=[

'DIRS': [os.path.join(BASE_DIR, 'templates')],

]

This how you can customize the admin template in Django as per your requirements.

I want to change certain css in admin django like base.css. Is it better to change directly in the django library? How can I override it in the best way?

asked Sep 9, 2011 at 4:06

rajan sthapit's user avatar

rajan sthapitrajan sthapit

3,98610 gold badges41 silver badges63 bronze badges

0

It depends a lot of what you want to do. Though first of all: do not overwrite it in the Django admin directly. You got two options I think are reasonable:

  1. If you want to change the appearance of the admin in general you should override admin templates. This is covered in details here: Overriding admin templates. Sometimes you can just extend the original admin file and then overwrite a block like {% block extrastyle %}{% endblock %} in django/contrib/admin/templates/admin/base.html as an example.
  2. If your style is model specific you can add additional styles via the Media meta class in your admin.py. See an example here:
class MyModelAdmin(admin.ModelAdmin):
    class Media:
        js = ('js/admin/my_own_admin.js',)    
        css = {
             'all': ('css/admin/my_own_admin.css',)
        }

answered Sep 9, 2011 at 4:38

Torsten Engelbrecht's user avatar

7

  • In settings.py, make sure your app is listed before admin in the INSTALLED_APPS.
  • Create (your-app)/templates/admin/base_site.html and put the <style> block into the {% block extrahead %}

Example:

{% extends "admin/base_site.html" %}
{% block extrahead %}
    <style>
        .field-__str__ {
            font-family: Consolas, monospace;
        }
    </style>
{% endblock %}

answered Jan 30, 2018 at 16:25

tivnet's user avatar

3

This solution will work for the admin site, I think it’s the cleanest way because it overrides base_site.html which doesn’t change when upgrading django.

Create in your templates directory a folder called admin in it create a file named base_site.html.

Create in your static directory under css a file called admin-extra.css .

Write in it all the custom css you want for your forms like: body{background: #000;}.

Paste this in the base_site.html:

{% extends "admin/base.html" %}
{% load static from staticfiles %} # This might be just {% load static %} in your ENV

{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}

{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "css/admin-extra.css" %}" />{% endblock %}

{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></h1>
{% endblock %}

{% block nav-global %}{% endblock %}

As mentioned in the comments:
make sure your app is before the admin app in INSTALLED_APPS, otherwise your template doesn’t override django’s

That’s It! you’re done

answered May 19, 2016 at 8:08

elad silver's user avatar

elad silverelad silver

8,8624 gold badges43 silver badges66 bronze badges

7

I just extended admin/base.html to include a reference to my own css file — at the end. The beauty of css is that you don’t have to touch existing definitions, just re-define.

answered Sep 9, 2011 at 5:33

Danny W. Adair's user avatar

Danny W. AdairDanny W. Adair

12.2k4 gold badges42 silver badges49 bronze badges

0

In your static directory, create a static/admin/css/base.css file.

Paste in Django’s default Admin CSS first, then add your customizations at the bottom.

answered Sep 6, 2013 at 2:26

Ryan Allen's user avatar

Ryan AllenRyan Allen

5,1254 gold badges25 silver badges33 bronze badges

4

If you want a global scope and you don’t want to think about overriding templates a mixin works really well for this. Put this code wherever you want:

class CSSAdminMixin(object):
    class Media:
        css = {
            'all': ('css/admin.css',),
        }

Then, make a CSS file called admin.css with your overrides, for example:

select[multiple] {
    resize: vertical;
}

Then, in whatever models you want, do:

class MyModelAdmin(admin.ModelAdmin, CSSAdminMixin):

And you’ll be all set.

answered Jul 26, 2017 at 16:51

mlissner's user avatar

mlissnermlissner

16.9k17 gold badges98 silver badges168 bronze badges

2

Have admin/css/changelists.css inside a folder in STATICFILES_DIRS, and it will user that changelists.css instead of the default admin one.

answered May 12, 2015 at 12:53

belteshazzar's user avatar

belteshazzarbelteshazzar

2,1332 gold badges20 silver badges30 bronze badges

It just so happens that using <style> tag inside {% block extrastyle %}{% endblock %} did not work for me when I wanted to override css. Theming support provides the correct way. All I was missing is {{ block.super }} :-

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

{% block extrastyle %}{{ block.super }}
<style>
--- your style ---
--- properties here ---
</style>
{% endblock %}

answered Aug 26, 2022 at 10:56

Aseem Yadav's user avatar

Aseem YadavAseem Yadav

7187 silver badges15 bronze badges

6 августа 2021

11 871

0

Время чтения ≈ 30 минут

Содержание:

  • Определение цифровой трансформации
  • Установка Django
  • Загрузка фикстур в Django
  • Кастомизация Django Admin
  • Модификация списка объектов с помощью list_display
  • Гиперссылки на страницы других объектов
  • Добавление фильтров на экран объектов
  • Изменение способа редактирования моделей
  • Переопределение шаблонов Django admin
  • Заключение

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

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

Благодаря этому руководству вы научитесь:

  • Добавлять столбцы атрибутов в списки объектов модели.
  • Создавать связи между объектами моделей.
  • Добавлять фильтры к списку объектов модели.
  • Добавлять поиск для списков объектов моделей.
  • Изменять формы редактирования объекта.
  • Переопределять административные шаблоны Django.

Предварительные требования

Чтобы пользоваться данным руководством наиболее эффективно, вы должны быть немного знакомы с Django, в частности с объектами моделей (model objects). Поскольку Django не часть стандартной библиотеки Python, будет лучше, если вы предварительно освоите «pip», «pyenv» или аналогичные инструменты виртуальной среды.

Это руководство было протестировано на Django 3.0.7. Но основные принципы неизменны со времён Django 2.0, так что всё должно работать на любой используемой версии ПО, хотя возможны небольшие отличия.

Панель администратора Django (Django admin panel) предоставляет веб-интерфейс для создания и управления объектами модели базы данных. Чтобы увидеть его в действии, нам сначала понадобится проект Django и несколько объектов модели.

Установим Django в чистую виртуальную среду:

python -m pip install django
django-admin startproject School
cd School
./manage.py startapp core
./manage.py migrate
./manage.py createsuperuser
Username: admin
Email address: admin@example.com
Password:
Password (again):

Сперва мы создаём новый проект Django под именем «School» и приложение, названное «core». После этого мы выполняем миграцию таблиц аутентификации и создаём пользователя с правами администратора.

Доступ к экранам (screens) Django admin предоставляется пользователями с флажками «staff» или «superuser». Поэтому для создания суперпользователя используем команду управления createsuperuser.

Также нужно изменить файл «School/settings.py», включив новое приложение Django под именем «core»:

# School/settings.py
# ...

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "core",    # Добавьте эту строку
]

В каталоге приложения «core» появятся файлы:

Из этих файлов нас интересуют два:

  1. «models.py» — определяет наши модели баз данных.
  2. «admin.py» — регистрирует эти модели с помощью Django admin.

Чтобы показать результат кастомизации админ панели Django, понадобится несколько моделей. Отредактируем файл «core/models.py»:

from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models

class Person(models.Model):
    last_name = models.TextField()
    first_name = models.TextField()
    courses = models.ManyToManyField("Course", blank=True)

    class Meta:
        verbose_name_plural = "People"

class Course(models.Model):
    name = models.TextField()
    year = models.IntegerField()

    class Meta:
        unique_together = ("name", "year", )

class Grade(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    grade = models.PositiveSmallIntegerField(
        validators=[MinValueValidator(0), MaxValueValidator(100)])
    course = models.ForeignKey(Course, on_delete=models.CASCADE)

Эти модели представляют учеников, посещающих курсы колледжа. Каждый курс («Course») имеет название («name») и год («year»), в котором его предлагают.

Каждый ученик («Person») имеет имя («first_name») и фамилию («last_name»). Он может посещать «0» или более курсов («courses»). Оценка («Grade») хранит процентные баллы, полученные учеником на курсе.

Диаграмма модели иллюстрирует отношения между объектами:

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

Каждую модель, которую Django будет отображать в интерфейсе администратора, нужно регистрировать. Сделать это можно в файле «admin.py». Модели из файла «core/models.py» регистрируются в соответствующем файле «core/admin.py».

from django.contrib import admin

from core.models import Person, Course, Grade

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    pass

@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
    pass

@admin.register(Grade)
class GradeAdmin(admin.ModelAdmin):
    pass

Почти готово. После миграции моделей базы данных можно запустить сервер разработки Django и увидеть результат:

./manage.py makemigrations
./manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, core, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  ...
  Applying core.0001_initial... OK
  Applying core.0002_auto_20200609_2120... OK
  Applying sessions.0001_initial... OK
./manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
Django version 3.0.7, using settings 'School.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Теперь, чтобы попасть в интерфейс администратора, пройдём по ссылке — http://127.0.0.1:8000/admin.

Нам предложат залогиниться. Воспользуемся учётной записью, созданной командой администратора «createsuperuser».

На начальной странице панели администратора приведены все зарегистрированные модели баз данных:

Теперь можно воспользоваться интерфейсом для создания объектов в нашей базе данных. Если кликнуть на имя модели, появится экран со списком всех объектов её базы данных. Вот список «Person»:

В начале список пуст, как и вся наша база данных Django. Внести ученика в базу данных можно, кликнув на элемент «ADD PERSON». После сохранения нас возвращают к списку объектов «Person»:

Хорошая новость в том, что теперь у нас есть объект. Плохая — строка «Person object (1)» не сообщает нам о нём ничего, кроме идентификатора («id»).

По умолчанию Django admin показывает каждый объект, вызывая для него метод «str()». Но мы покажем, как сделать этот экран чуть полезнее. Нужно просто добавить метод «.__str__()» в класс «Person» в файле «core/models.py».

class Person(models.Model):
    last_name = models.TextField()
    first_name = models.TextField()
    courses = models.ManyToManyField("Course", blank=True)

    def __str__(self):
        return f"{self.last_name}, {self.first_name}"

Добавление метода «Person.__str__()» изменяет интерфейс так, чтобы для каждого объекта «Person» отображались имя и фамилия. Чтобы увидеть изменения, можно обновить экран:

Стало гораздо лучше! Теперь мы видим об объекте «Person» уже какую-то информацию. Неплохая идея — добавить аналогичные методы для объектов «Course» и «Grade».

class Course(models.Model):
    # ...

    def __str__(self):
        return f"{self.name}, {self.year}"

class Grade(models.Model):
    # ...

    def __str__(self):
        return f"{self.grade}, {self.person}, {self.course}"

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

Загрузка фикстур в Django

Django позволяет загружать данные из/в базы данных при помощи файлов, называемых фикстурами. Для того, чтобы воспользоваться этим способом, скопируйте следующее содержимое в файл «core/fixtures/school.json»:

[
    {
        "model": "core.person",
        "pk": 1,
        "fields": {
            "last_name": "Harris",
            "first_name": "Xander",
            "courses": [
                1,
                3
            ]
        }
    },
    {
        "model": "core.person",
        "pk": 3,
        "fields": {
            "last_name": "Rosenberg",
            "first_name": "Willow",
            "courses": [
                1,
                2,
                3
            ]
        }
    },
    {
        "model": "core.person",
        "pk": 16,
        "fields": {
            "last_name": "Summers",
            "first_name": "Buffy",
            "courses": [
                1,
                2,
                3
            ]
        }
    },
    {
        "model": "core.course",
        "pk": 1,
        "fields": {
            "name": "CompSci G11",
            "year": 1998
        }
    },
    {
        "model": "core.course",
        "pk": 2,
        "fields": {
            "name": "Psych 101",
            "year": 1999
        }
    },
    {
        "model": "core.course",
        "pk": 3,
        "fields": {
            "name": "Library Science G10",
            "year": 1997
        }
    },
    {
        "model": "core.grade",
        "pk": 1,
        "fields": {
            "person": 16,
            "grade": 68,
            "course": 1
        }
    },
    {
        "model": "core.grade",
        "pk": 2,
        "fields": {
            "person": 16,
            "grade": 87,
            "course": 2
        }
    },
    {
        "model": "core.grade",
        "pk": 3,
        "fields": {
            "person": 16,
            "grade": 76,
            "course": 3
        }
    },
    {
        "model": "core.grade",
        "pk": 4,
        "fields": {
            "person": 1,
            "grade": 58,
            "course": 1
        }
    },
    {
        "model": "core.grade",
        "pk": 5,
        "fields": {
            "person": 1,
            "grade": 58,
            "course": 3
        }
    },
    {
        "model": "core.grade",
        "pk": 6,
        "fields": {
            "person": 3,
            "grade": 98,
            "course": 3
        }
    },
    {
        "model": "core.grade",
        "pk": 7,
        "fields": {
            "person": 3,
            "grade": 97,
            "course": 2
        }
    }
]

Создав файл, можно воспользоваться административной командой «loaddata». Это загрузит его в нашу базу данных.

./manage.py loaddata school
Installed 13 object(s) from 1 fixture(s)

Теперь в нашей базе есть тестовые объекты «Person», «Course» и «Grade».

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

Кастомизация Django Admin

Создатели фреймворка Django не просто сделали для него панель администратора, но и заложили возможность тонкой настройки проектов на Django через неё.

Регистрируя ранее объект «PersonAdmin», мы унаследовали его из класса «admin.ModelAdmin». Большая часть кастомизации Django admin выполняется через изменение объектов «ModelAdmin», которые специально предназначены для этого.

У класса «ModelAdmin» больше тридцати атрибутов и почти пятьдесят методов. Для тонкой настройки отображения панели администратора и управления объектами интерфейса можно использовать каждый из них. В документации подробно описаны все эти опции.

В довершение ко всему, панель администратора создана с использованием шаблонов Django. Механизм шаблонов Django позволяет переопределить существующие шаблоны. И, поскольку панель администратора — просто очередной набор шаблонов, её HTML-код полностью открыт для изменений.

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

Django admin состоит из трёх основных частей:

  1. «Индекс приложения» (app index) отображает перечень зарегистрированных моделей.
  2. «Списки объектов» (change lists) автоматически создаются для каждой зарегистрированной модели и перечисляют её объекты.
  3. «Формы изменений» (change forms) позволяют добавлять или изменять эти объекты.

В примере выше индекс приложения показал объекты «Person», «Course» и «Grade». Кликнув на элемент «People», мы видим списки объектов «Person». На странице списка объектов «Person» можно кликнуть на имя Баффи Саммерс (Buffy Summers) и попасть на форму изменения для редактирования данных.

Модификация списка объектов с помощью list_display

Определение функции «.__str__()» — быстрый способ поменять представление объектов «Person» с (на первый взгляд) бессмысленного набора символов на понятные данные. Это представление также используется для выпадающих списков и множественного выбора, поэтому лучше сделать его как можно понятнее и нагляднее.

Помимо изменения строки представления объекта, страницы списков объектов можно настроить и по другим параметрам. Атрибут «list_display» объекта «admin.ModelAdmin» указывает, какие столбцы отобразятся в списке объектов.

Это значение представляет собой кортеж атрибутов моделируемого объекта. Например, изменим в файле «core/admin.py» объект «PersonAdmin»:

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    list_display = ("last_name", "first_name")

Эти команды модифицируют наш список объектов «Person» так, чтобы для каждого объекта «Person» отображались атрибуты «last_name» и «first_name».

Каждый атрибут показан на столбце страницы:

На оба столбца можно кликнуть для сортировки страницы по данным столбца. Django admin также учитывает атрибут «ordering» раздела «Meta»:

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    list_display = ("last_name", "first_name")

Если добавить атрибут «ordering», то по умолчанию все запросы к объекту «Person» будут возвращаться отсортированными сначала по фамилии («last_name»), а затем по имени (first_name»). Django станет использовать такой порядок по умолчанию как в панели администратора, так и при получении объектов.

Кортеж «list_display» может отсылать к любому атрибуту отображаемого объекта. Он может также ссылаться на методы самого объекта «admin.ModelAdmin».

Снова изменим объект «PersonAdmin»:

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    list_display = ("last_name", "first_name", "show_average")

    def show_average(self, obj):
        from django.db.models import Avg
        result = Grade.objects.filter(person=obj).aggregate(Avg("grade"))
        return result["grade__avg"]

В приведённом выше коде мы добавили в панель администратора столбец, показывающий оценки учеников. Для каждого объекта в списке вызывается функция  «show_average()».

Параметр «obj» обозначает объект отображаемой строки таблицы. В нашем случае мы используем его для запроса к соответствующим объектам «Grade», получая усреднённую оценку ученика по функции «Grade.grade». Результат можно увидеть здесь:

Нужно учесть, что средняя оценка для объекта модели «Person» должна вычисляться внутри этого объекта, поскольку данные будут использоваться где-то ещё, а не только в Django admin. Если у нас есть такой метод, его можно добавить в атрибут «list_display».

Этот пример демонстрирует возможности объектов «ModelAdmin», но, по всей видимости, это не лучшее решение для нашего кода.

По умолчанию сортировка выполняется только для столбцов с атрибутами объекта, к которым «show_average()» не относится. Дело в том, что сортировка выполняется не на уровне отображения результатов, а на основании выборки «QuerySet». Есть способы сортировки и для таких столбцов, но их разбор выходит за рамки рассматриваемой темы.

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

def show_average(self, obj):
    result = Grade.objects.filter(person=obj).aggregate(Avg("grade"))
    return result["grade__avg"]

show_average.short_description = "Average Grade"

По умолчанию Django не допускает ввода HTML-кода в строках, на случай, если строка получена от пользователя. Чтобы его задействовать, нужно использовать функцию «format_html()»:

def show_average(self, obj):
    from django.utils.html import format_html

    result = Grade.objects.filter(person=obj).aggregate(Avg("grade"))
    return format_html("<b><i>{}</i></b>", result["grade__avg"])

show_average.short_description = "Average"

Теперь у столбца функции «show_average()» новый заголовок «Average», а строки отформатированы курсивом:

К сожалению, в Django пока не добавили поддержку f-строк для функции «format_html()». Поэтому придётся обойтись синтаксисом «str.format()».

Гиперссылки на страницы других объектов

Одни объекты часто ссылаются на другие, используя внешние ключи. Можно включить в кортеж «list_display» метод, возвращающий HTML-ссылку.

Изменим класс «CourseAdmin» в файле «core/admin.py» таким образом:

from django.urls import reverse
from django.utils.http import urlencode

@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
    list_display = ("name", "year", "view_students_link")

    def view_students_link(self, obj):
        from django.utils.html import format_html
        count = obj.person_set.count()
        url = (
            reverse("admin:core_person_changelist")
            + "?"
            + urlencode({"courses__id": f"{obj.id}"})
        )
        return format_html('<a href="{}">{} Students</a>', url, count)

    view_students_link.short_description = "Students"

Благодаря этому коду список объектов «Course» будет иметь три столбца:

  1. «NAME» — название курса.
  2. «YEAR» — год, в котором предлагается курс
  3. «STUDENTS» — гиперссылка с указанием числа учеников

Изменения можно увидеть на скриншоте:

Кликнув на ссылку «2 Students», мы попадём на страницу со списком объектов «Person», к которой применён фильтр. Отфильтрованная страница показывает только учеников курса «Psych 101» — Баффи (Buffy) и Уиллоу (Willow). Ксандер в университет не попал.

Приведённый код использует функцию «reverse()» для нахождения гиперссылки в Django admin. Также можно найти любую страницу панели администратора.

Используется следующий формат именования:

"admin:%(app)s_%(model)s_%(page)"

Он состоит из нескольких частей:

  • «admin:» — ключевое слово.
  • «app» — название приложения.
  • «model»— объект модели.
  • «page» — страница административной панели Django.

Вернёмся к примеру с функцией «view_students_link()». Там для получения ссылки на страницу со списком объектов «Person» приложения «core» использовался метод «admin:core_person_changelist».

Вот доступные URL-адреса:

Страница URL-адрес Назначение
Список объектов %(app)s_%(model)s_changelist Страница со списком объектов модели.
Добавление %(app)s_%(model)s_add Страница создания объектов
История %(app)s_%(model)s_history Страница с историей изменения объекта. В качестве параметра принимает object_id.
Удаление %(app)s_%(model)s_delete Страница удаления объекта. В качестве параметра принимает object_id.
Изменение %(app)s_%(model)s_change Страница изменения объекта. В качестве параметра принимает object_id.

Страницу объекта можно фильтровать, добавляя в URL запрос из строковой переменной. Он изменит выборку «QuerySet», используемую для формирования страницы.

В приведённом выше примере запрос из строковой переменной «?courses__id={obj.id}» фильтрует список «Person», оставляя лишь объекты с совпадающим значением «Person.course».

Для выборок «QuerySet» эти фильтры поддерживают запросы типа «field lookups», использующие двойные подчерки («__»). Можно получить доступ к атрибутам соответствующих объектов или использовать такие модификаторы фильтров, как «__exact» и «__startswith».

Подробности о том, чего можно достичь с помощью использования атрибута «list_display», можно найти в документации по панели администратора Django.

Добавление фильтров на экран объектов

Помимо фильтрации списка объекта через URL, можно добавить фильтр с помощью встроенного виджета. Добавим для объекта «CourseAdmin» атрибут «list_filter» в файле «core/admin.py»:

@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
    list_display = ("name", "year", "view_students_link")
    list_filter = ("year", )
# ...

Атрибут «list_filter» отобразит на странице новый раздел со списком ссылок. В нашем случае это ссылки для фильтрации страниц по году. Список фильтра автоматически наполняется значениями «year» объектов «Course» из базы данных:

Кликая на год («year») справа страницы, мы изменим список, включив только объекты «Course» с заданным значением «year».

Фильтрация также возможна на основании атрибутов связанных объектов при использовании синтаксиса «field lookup» («__»). Например, можно отфильтровать объекты «GradeAdmin» с помощью «course__year». Это выведет только объекты «Grade» за определённый год.

Если нужны расширенные возможности фильтрации, то можно даже создавать объекты фильтра (filter objects), задающие атрибуты поиска и нужную выборку «QuerySet».

Добавление поиска на экран объектов

Фильтры — не единственный способ уменьшить объёмы данных на экране. Django admin также поддерживает поиск с помощью опции «search_fields», которая добавляет на экран поле поиска (search box). Его связывают с кортежем, содержащим имена полей, которые будут использованы для формирования строкового запроса к базе данных.

Всё, что пользователь введёт в поле поиска, будет использовано в качестве фильтра полей для выборки «QuerySet». Условие будет разделено операторами «OR». По умолчанию каждый поисковый параметр окружён знаками «%». Это означает, что если мы будем искать  «r», то в результат попадёт любое слово, содержащее «r». Можно указать поле поиска и точнее, используя модификатор «__».

Отредактируем объект «PersonAdmin» в файле «core/admin.py» так:

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    search_fields = ("last_name__startswith", )

В приведённом выше коде поиск основан на фамилии. Модификатор «__startswith» ограничивает поиск по фамилии теми вхождениями, которые начинаются на запрос. Поиск по «R» даст такой результат:

При каждом поиске на странице объектов, Django admin вызывает метод «get_search_results()» нашего объекта «admin.ModelAdmin». Этот метод возвращает выборку «QuerySet» с результатом поиска. В официальной документации также показано, как настроить поиск, перегружая метод и изменяя выборку «QuerySet».

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

Кастомизация возможна не только для страницы списка объектов. Экраны, используемые для добавления и удаления объектов, основаны на объекте «ModelForm». Django автоматически генерирует форму, основываясь на редактируемой модели.

Редактируя опцию «fields», можно управлять включением и порядком полей. Изменим наш объект «PersonAdmin», добавив атрибут «fields»:

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    fields = ("first_name", "last_name", "courses")
# ...

Теперь страницы добавления («Add») и изменения («Change») для объектов «Person» выводят атрибут имя («first_name») перед фамилией («last_name»), хотя в самой модели порядок обратный:

За создание нашего объекта «ModelForm» отвечает метод «ModelAdmin.get_form()». Для изменения формы этот метод можно переопределить.

Добавим в объект «PersonAdmin» такой метод:

def get_form(self, request, obj=None, **kwargs):
    form = super().get_form(request, obj, **kwargs)
    form.base_fields["first_name"].label = "First Name (Humans only!):"
    return form

Теперь при отображении страниц добавления или изменения учеников подпись «first_name» будет кастомизирована.

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

Если нас не устраивает форма «ModelForm», созданная Django admin, можно задействовать атрибут «form» для регистрации специальной формы. Сделать это можно, добавив и изменив кое-что в файле «core/admin.py»:

from django import forms

class PersonAdminForm(forms.ModelForm):
    class Meta:
        model = Person
        fields = "__all__"

    def clean_first_name(self):
        if self.cleaned_data["first_name"] == "Spike":
            raise forms.ValidationError("No Vampires")

        return self.cleaned_data["first_name"]

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    form = PersonAdminForm
# ...

Этот код вводит дополнительную проверку на страницах добавления и изменения объектов «Person».

У механизма валидации объектов «ModelForm» широкие возможности. В нашем случае, поле «first_name» не допускает введения имени «Спайк» (Spike). Метод «ValidationError» не даст ученикам с таким именем зарегистрироваться:

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

Добавление поиска на экран объектов

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

Можно увидеть все её шаблоны, заглянув в виртуальную среду пакета Django:

Движок шаблонов Django имеет определённый порядок их загрузки. Загружая какой-либо шаблон, он использует первый же, совпадающий по имени. Административные шаблоны можно переопределить, используя ту же структуру каталогов и имена файлов.

Административные шаблоны находятся в двух каталогах:

  1. admin — для страниц объектов модели.
  2. registration — для смены пароля, а также входа и выхода из системы.

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

Нужный нам файл — «registration/logged_out.htm»l. Начнём с создания каталога в проекте «School»:

mkdir -p templates/registration

Теперь расскажем Django о нашем новом каталоге шаблонов при помощи файла «School/settings.py». Находим указатель «TEMPLATES» и добавляем каталог в список «DIR»:

# School/settings.py
# ...

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",

        // Добавьте каталог с шаблонами через опцию DIR:
        "DIRS": [os.path.join(BASE_DIR, "templates"), ],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]

Движок шаблонов ищет каталоги в опции «DIR» прежде, чем в каталогах приложения. Поэтому всё, что совпадает по имени с административными шаблонами, будет загружено оттуда. Чтобы увидеть всё в действии, скопируем файл «logged_out.html» в наш каталог «templates/registration», а затем отредактируем его:

{% extends "admin/base_site.html" %}
{% load i18n %}

{% block breadcrumbs %}<div class="breadcrumbs"><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></div>{% endblock %}

{% block content %}

<p>You are now leaving Sunnydale</p>

<p><a href="{% url 'admin:index' %}">{% trans 'Log in again' %}</a></p>

{% endblock %}

Итак, мы настроили под себя страницу выхода из системы. Если нажать «LOG OUT», появится такое сообщение:

Шаблоны Django admin глубоко вложены и не вполне интуитивно понятны, но при необходимости у нас есть полный контроль над их отображением. Некоторые пакеты, включая Grappelli и Django Admin Bootstrap, меняют шаблоны Django admin на собственные, чтобы изменить внешний облик административной панели.

Django Admin Bootstrap пока не совместим с Django 3, а Grappelli добавил поддержку сравнительно недавно, поэтому проблемы пока не исключены. Но если хотите увидеть всю мощь переопределения административных шаблонов, познакомьтесь с этими проектами!

Заключение

Панель администратора Django — мощный встроенный инструмент со множеством возможностей. Она позволяет создавать, обновлять и удалять объекты вашей базы данных с помощью веб-интерфейса.

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

  • Регистрировать объекты модели с помощью Django admin.
  • Добавлять атрибуты как столбцы списка объектов.
  • Создавать значения столбцов с помощью автоматически вычисляемого содержимого (calculated content).
  • Делать перекрёстные ссылки для административных страниц
  • Фильтровать страницу списка объектов с помощью строкового запроса
  • Добавлять поиск для ваших списков объектов
  • Кастомизировать автоматический объект «ModelForm»
  • Изменять HTML-код административных шаблонов Django 

Этот обзор затрагивает только основы. Настойки конфигурации Django admin гораздо шире. Изучив официальную документацию, можно освоить такие возможности, как встроенные формы (inline forms), множественные сайты администратора (admin sites), массовое редактирование, автозаполнение и многое другое.

Нужна надёжная база для размещения сайта? Выбирайте виртуальные сервера от Eternalhost с технической поддержкой 24/7 и бесплатной защитой от DDoS!

Автор оригинала: Christopher Trudeau

Оцените материал:


[Всего голосов: 0    Средний: 0/5]

Админ-панель Django выглядит достаточно неплохо: не раздражает цвет, адаптивный дизайн, всё расположено
довольно логично… Тем не менее, многие не хотят видеть надпись «Django», да и а целом разукрасить
админку в «свои цвета».

Изображение Python 3.11. Что нового?

Настраиваем отображение заголовка, вкладки

Самое первое, что бросается в глаза — страница логина, на которой открытым текстом говорится о фреймфорке,
первая страница после логина — также приветствие от Django, да и название вкладки намекает на нашего веб-друга.
Чтобы поменять всё это «безобразие», нужно в admin.py сделать всего 3 настройки:

from django.contrib import admin

admin.site.site_header = "Лучшая админка"
admin.site.site_title = "Панель администрирования"
admin.site.index_title = "Добро пожаловать в админку"

Ну вот и готова наша BolgenCMS — можно уже продавать. Хотя и раньше можно было — лицензия позволяет.
Но если всё же вам важно изменить эти надписи — теперь можете изменить.

Убираем «ненужные» разделы админки

При первом входе в админ-панель Django можно увидеть два раздела для редактирования пользователей и групп.
Если они вам по какой-то причине мешают — их можно также просто убрать. Для этого «разрегистрируем» эти админки:

from django.contrib import admin
from django.contrib.auth.models import User, Group

admin.site.unregister(User)
admin.site.unregister(Group)

В предыдущей заметке о настройке Django
админки мы напротив — регистрировали свою модель в админку. Здесь же мы удаляем «ненужное».

Есть время создавать админки, а есть время их удалять…

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

Понятно, что у лучшей админки должен быть как минимум свой логотип. Чтобы добавить логотип, нам нужно для начала
включить работу со статическими файлами. Поэтому создадим в корне проекта папку static и зарегистрируем её
в settings.py:

STATIC_URL = '/static/'  # Вот под этой строчкой
STATICFILES_DIRS = [f'{BASE_DIR}/static/']

Добавим в нашу папку для статики файл логотипа pony.png.

Теперь нам нужно переопределить шаблон для заголовка страницы — templates/admin/base_site.html.
Для переопределения шаблонов я обычно завожу отдельную папку либо в главном приложении, либо в корне проекта.
Чтобы это сделать, немного отредактируем переменную TEMPLATES в sessings.py:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [f'{BASE_DIR}/templates/'],  # Изменилась эта строчка
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

Сам файл шаблона заголовка админ-панели создаём в файле templates/admin/base_site.html:

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

{% load static %}

{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}

{% block branding %}
<h1 id="site-name">
    <a href="{% url 'admin:index' %}">
        <img src="{% static 'pony.png' %}" height="40px" />
        {{ site_header }}
    </a>
</h1>
{% endblock %}

{% block nav-global %}{% endblock %}

Не знаю как у вас, а у меня теперь рядом с заголовком красуется поняшка.

Аналогичным методом можно переопределить и другие шаблоны. Оригиналы можно найти в пакете django,
лежат они в директории django/contrib/admin/templates/admin. Либо же, если просто хотите поменять
что-то в цветовой схеме — можете переопределить файл /static/admin/css/base.css.

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Как изменить стили css через js
  • Как изменить стили bootstrap
  • Как изменить стикеры на клавиатуре
  • Как изменить стикеры на андроид
  • Как изменить стикеры мемоджи на айфоне

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии