Перейти к содержанию

Администрирование

Чтобы настроить админ-панель, перейдём в файл admin.py в нашем приложении.

Первым делом настроим заголовки страницы:

from django.contrib import admin

admin.site.site_title = "Админ-панель Авиаперелётов"
admin.site.site_header = "Админ-панель Авиаперелётов"

Далее необходимо зарегистрировать все модели. Чтобы дополнительно их настроить, создадим новые классы, наследуемые от admin.ModelAdmin и повесим на них декоратор @admin.register(НазваниеМодели). Внутри классов переопределим следующие атрибуты:

  • list_display - то, что будет отображаться в табличном виде;
  • list_filter - фильтры в таблице;
  • search_fields - по каким полям искать нужные строчки;
  • readonly_fields - "самописная" информация, не зависящая от конкретного поля. Будет отображаться в "карточке" объекта.

С помощью декоратора @admin.display можно создать новые "поля" в табличном представлении модели или в "карточках" объектов.

Доступ к полям "соединённых" таблиц можно получить, используя двойное подчёркивание (__).

from django.contrib import admin
from django.urls import reverse
from django.utils import timezone
from django.utils.safestring import mark_safe

from .models import Airline


@admin.register(Airline)
class AirlineAdmin(admin.ModelAdmin):
    list_display = ("name", "get_flights_count")
    search_fields = ("name",)
    readonly_fields = ("get_flights",)

    @admin.display(description="Количество рейсов")
    def get_flights_count(self, obj):
        return f"{obj.flights.count()}"

    @admin.display(description="Рейсы")
    def get_flights(self, obj):
        formatted_flights = []

        for flight in obj.flights.select_related("airline").all():
            flight_url = reverse(f"admin:{flight._meta.app_label}_{flight._meta.model_name}_change", args=(flight.pk,))
            type_ = flight.get_type_display()
            gate = flight.gate
            date = timezone.localtime(flight.date)

            formatted_flights.append(
                f"<a href='{flight_url}'>{type_}, {gate} - {date.strftime('%d.%m.%y %H:%M')}</a>"
            )

        return mark_safe("<br>".join(formatted_flights))

В этом классе определим новый метод, возвращающий количество рейсов у авикомпании. Для этого вызовем метод .count() у атрибута flights и узнаем количество объектов в запросе. Название этого метода введём в list_display, чтобы отобразить это количество в таблице для каждой авиакомпании.

Также определим метод get_flights, который мы введём в readonly_fields. В этом методе проитерируемся по всем рейсам и соберём информацию о каждом из них, чтобы вывести её в карточках авиакомпаний.

Также вставим ссылки на карточки соответствующих рейсов. Для этого вызовем функцию django.urls.reverse(), первым аргументом которой будет ссылка на изменение объекта в админ-панели. Получим её, используя защищённый атрибут _meta и его атрибуты app_label и model_name, а также значение первичного ключа объекта.

Занесём каждую строчку в список и затем объединим с помощью метода .join, где разделителем будет тэг <br>. Так как Django по умолчанию избегает HTML тэгов в целях безопасности, пометим этот текст как безопасный с помощью функции mark_safe.

Список авиакомпаний
Список авиакомпаний

Информация об авикомпании
Информация об авикомпании

from django.contrib import admin
from django.urls import reverse
from django.utils.safestring import mark_safe

from .models import Flight


@admin.register(Flight)
class FlightAdmin(admin.ModelAdmin):
    list_display = ("airline", "type", "gate", "date")
    search_fields = ("airline__name",)
    list_filter = ["airline", "type", "gate"]
    readonly_fields = ("get_bookings",)

    @admin.display(description="Брони")
    def get_bookings(self, obj):
        formatted_bookings = []

        for booking in obj.bookings.select_related("user").all():
            booking_url = reverse(
                f"admin:{booking._meta.app_label}_{booking._meta.model_name}_change", args=(booking.pk,)
            )
            user_full_name = f"{booking.user.last_name} {booking.user.first_name}"
            user_username = booking.user.username
            user = f"<a href='{booking_url}'>{user_full_name if user_full_name != ' ' else user_username}</a>"
            registered = "✅" if booking.registered else "❌"
            ticket = str(booking.ticket) if booking.ticket else ""

            formatted_bookings.append(f"{user} ({registered}{', ' + ticket if ticket else ''})")

        return mark_safe("<br>".join(formatted_bookings))

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

Список рейсов
Список авиакомпаний

Информация о рейсе
Информация о рейсе

from django.contrib import admin
from django.urls import reverse
from django.utils import timezone
from django.utils.safestring import mark_safe

from .models import Booking


@admin.register(Booking)
class BookingAdmin(admin.ModelAdmin):
    list_display = ("get_user", "get_airline", "get_type", "get_gate", "get_date", "registered", "ticket")
    search_fields = ("user__last_name", "user__first_name", "flight__airline")
    list_filter = ["flight__airline", "flight__type", "flight__gate", "registered"]
    list_editable = ("registered", "ticket")

    @admin.display(ordering="user__last_name", description="Пассажир")
    def get_user(self, obj):
        full_name = f"{obj.user.last_name} {obj.user.first_name}"
        return full_name if full_name != " " else obj.user.username

    @admin.display(ordering="flight__airline", description="Авиакомпания")
    def get_airline(self, obj):
        return obj.flight.airline

    @admin.display(ordering="flight__type", description="Тип")
    def get_type(self, obj):
        return obj.flight.get_type_display()

    @admin.display(ordering="flight__gate", description="Гейт")
    def get_gate(self, obj):
        return obj.flight.gate

    @admin.display(ordering="flight__date", description="Дата")
    def get_date(self, obj):
        return obj.flight.date

Список броней
Список броней

from django.contrib import admin

from .models import Feedback


@admin.register(Feedback)
class FeedbackAdmin(admin.ModelAdmin):
    list_display = ("get_user", "get_airline", "get_type", "get_gate", "get_date", "text", "rating", "date")
    search_fields = ("user__last_name", "user__first_name", "flight__airline")
    list_filter = ["flight__airline", "flight__type", "flight__gate", "rating"]

    @admin.display(ordering="user__last_name", description="Пассажир")
    def get_user(self, obj):
        return f"{obj.user.last_name} {obj.user.first_name}"

    @admin.display(ordering="flight__airline", description="Авиакомпания")
    def get_airline(self, obj):
        return obj.flight.airline

    @admin.display(ordering="flight__type", description="Тип")
    def get_type(self, obj):
        return obj.flight.get_type_display()

    @admin.display(ordering="flight__gate", description="Гейт")
    def get_gate(self, obj):
        return obj.flight.gate

    @admin.display(ordering="flight__date", description="Дата рейса")
    def get_date(self, obj):
        return obj.flight.date

Список отзывов
Список отзывов