Администрирование
Чтобы настроить админ-панель, перейдём в файл 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