"""
Административная панель для расписания.
"""
from django.contrib import admin
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _
from .models import Lesson, LessonTemplate, TimeSlot, Availability, Subject, MentorSubject
@admin.register(Lesson)
class LessonAdmin(admin.ModelAdmin):
"""Административная панель для занятий."""
list_display = [
'title', 'mentor', 'client', 'start_time',
'duration', 'status_badge', 'created_at'
]
list_filter = [
'status', 'start_time', 'mentor', 'subject', 'mentor_subject', 'created_at'
]
search_fields = [
'title', 'description', 'subject__name', 'mentor_subject__name', 'subject_name',
'mentor__email', 'mentor__first_name', 'mentor__last_name',
'client__user__email', 'client__user__first_name', 'client__user__last_name'
]
date_hierarchy = 'start_time'
readonly_fields = [
'end_time', 'created_at', 'updated_at',
'cancelled_at'
]
fieldsets = (
(_('Участники'), {
'fields': ('mentor', 'client')
}),
(_('Время'), {
'fields': ('start_time', 'duration', 'end_time')
}),
(_('Информация'), {
'fields': ('title', 'description', 'subject', 'mentor_subject', 'subject_name', 'template')
}),
(_('Статус'), {
'fields': ('status',)
}),
(_('Отмена'), {
'fields': (
'cancelled_by', 'cancellation_reason', 'cancelled_at'
),
'classes': ('collapse',)
}),
(_('Перенос'), {
'fields': ('rescheduled_from',),
'classes': ('collapse',)
}),
(_('Дополнительно'), {
'fields': (
'meeting_url', 'mentor_notes',
'reminder_sent'
),
'classes': ('collapse',)
}),
(_('Даты'), {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def status_badge(self, obj):
"""Отображение статуса с цветом."""
colors = {
'scheduled': '#3B82F6', # синий
'in_progress': '#10B981', # зеленый
'completed': '#6B7280', # серый
'cancelled': '#EF4444', # красный
'rescheduled': '#F59E0B', # оранжевый
}
color = colors.get(obj.status, '#6B7280')
return format_html(
'{}',
color,
obj.get_status_display()
)
status_badge.short_description = 'Статус'
def get_queryset(self, request):
"""Оптимизация запросов."""
return super().get_queryset(request).select_related(
'mentor', 'client', 'client__user', 'template',
'cancelled_by', 'rescheduled_from', 'subject', 'mentor_subject'
)
@admin.register(LessonTemplate)
class LessonTemplateAdmin(admin.ModelAdmin):
"""Административная панель для шаблонов занятий."""
list_display = [
'title', 'mentor', 'subject', 'duration',
'is_active', 'lessons_count', 'created_at'
]
list_filter = ['is_active', 'subject', 'mentor_subject', 'created_at']
search_fields = [
'title', 'description', 'subject__name', 'mentor_subject__name', 'subject_name',
'mentor__email', 'mentor__first_name', 'mentor__last_name'
]
readonly_fields = ['created_at', 'updated_at']
fieldsets = (
(_('Владелец'), {
'fields': ('mentor',)
}),
(_('Информация'), {
'fields': ('title', 'description', 'subject', 'mentor_subject', 'subject_name', 'duration')
}),
(_('Настройки'), {
'fields': ('is_active', 'meeting_url', 'color')
}),
(_('Даты'), {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def lessons_count(self, obj):
"""Количество занятий созданных из шаблона."""
return obj.lessons.count()
lessons_count.short_description = 'Занятий создано'
def get_queryset(self, request):
"""Оптимизация запросов."""
return super().get_queryset(request).select_related('mentor', 'subject', 'mentor_subject')
@admin.register(TimeSlot)
class TimeSlotAdmin(admin.ModelAdmin):
"""Административная панель для временных слотов."""
list_display = [
'mentor', 'start_time', 'end_time',
'availability_badge', 'is_recurring', 'created_at'
]
list_filter = [
'is_available', 'is_booked', 'is_recurring',
'start_time', 'created_at'
]
search_fields = [
'mentor__email', 'mentor__first_name', 'mentor__last_name'
]
date_hierarchy = 'start_time'
readonly_fields = ['created_at', 'updated_at']
fieldsets = (
(_('Ментор'), {
'fields': ('mentor',)
}),
(_('Время'), {
'fields': ('start_time', 'end_time')
}),
(_('Статус'), {
'fields': ('is_available', 'is_booked', 'lesson')
}),
(_('Повторение'), {
'fields': ('is_recurring', 'recurring_day')
}),
(_('Даты'), {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def availability_badge(self, obj):
"""Отображение доступности."""
if obj.is_booked:
return format_html(
'Забронирован'
)
elif obj.is_available:
return format_html(
'Доступен'
)
else:
return format_html(
'Недоступен'
)
availability_badge.short_description = 'Доступность'
def get_queryset(self, request):
"""Оптимизация запросов."""
return super().get_queryset(request).select_related('mentor', 'lesson')
@admin.register(Availability)
class AvailabilityAdmin(admin.ModelAdmin):
"""Административная панель для доступности."""
list_display = [
'mentor', 'day_display', 'time_range',
'is_recurring', 'is_active', 'created_at'
]
list_filter = [
'is_active', 'is_recurring', 'day_of_week', 'created_at'
]
search_fields = [
'mentor__email', 'mentor__first_name', 'mentor__last_name', 'notes'
]
readonly_fields = ['created_at', 'updated_at']
fieldsets = (
(_('Ментор'), {
'fields': ('mentor',)
}),
(_('Время'), {
'fields': ('day_of_week', 'specific_date', 'start_time', 'end_time')
}),
(_('Тип'), {
'fields': ('is_recurring', 'is_active')
}),
(_('Исключения'), {
'fields': ('exception_dates', 'notes'),
'classes': ('collapse',)
}),
(_('Даты'), {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def day_display(self, obj):
"""Отображение дня."""
if obj.is_recurring and obj.day_of_week is not None:
return obj.get_day_of_week_display()
elif obj.specific_date:
return obj.specific_date.strftime('%d.%m.%Y')
return '-'
day_display.short_description = 'День'
def time_range(self, obj):
"""Отображение временного диапазона."""
return f"{obj.start_time.strftime('%H:%M')} - {obj.end_time.strftime('%H:%M')}"
time_range.short_description = 'Время'
def get_queryset(self, request):
"""Оптимизация запросов."""
return super().get_queryset(request).select_related('mentor')
@admin.register(Subject)
class SubjectAdmin(admin.ModelAdmin):
"""Административная панель для предметов."""
list_display = ['name', 'is_active', 'lessons_count', 'created_at']
list_filter = ['is_active', 'created_at']
search_fields = ['name']
readonly_fields = ['created_at', 'updated_at']
fieldsets = (
(_('Информация'), {
'fields': ('name', 'is_active')
}),
(_('Даты'), {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def lessons_count(self, obj):
"""Количество занятий с этим предметом."""
return obj.lessons.count()
lessons_count.short_description = 'Занятий'
@admin.register(MentorSubject)
class MentorSubjectAdmin(admin.ModelAdmin):
"""Административная панель для кастомных предметов менторов."""
list_display = ['name', 'mentor', 'usage_count', 'created_at']
list_filter = ['created_at']
search_fields = ['name', 'mentor__email', 'mentor__first_name', 'mentor__last_name']
readonly_fields = ['created_at', 'updated_at']
fieldsets = (
(_('Информация'), {
'fields': ('mentor', 'name', 'usage_count')
}),
(_('Даты'), {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def get_queryset(self, request):
"""Оптимизация запросов."""
return super().get_queryset(request).select_related('mentor')