from django.forms import TypedMultipleChoiceField from django.contrib import admin, messages from django.http import HttpRequest from django.db.models.query import QuerySet from django.utils.safestring import SafeText from django_admin_action_forms import AdminActionFormsMixin, AdminActionForm, action_with_form from import_export import fields from import_export.admin import ImportMixin from import_export.tmp_storages import CacheStorage from import_export.resources import ModelResource from ..models.aircrafts import AircraftTypes from ..models.missions import MissionProfile from ..actions.assign_aircraft import assign_aircraft from datetime import timedelta from typing import Any, Dict, List # Resource Class for Student data import class MissionProfileResource(ModelResource): mtype = fields.Field(attribute="mtype", column_name="mtype") mnum = fields.Field(attribute="mnum", column_name="mnum") duration = fields.Field(attribute="duration", column_name="duration") # Cleanup fields before entering def before_import_row(self, row: dict[str, str | Any], **kwargs): row["mtype"] = SafeText(row["mtype"].upper().strip()) row["mnum"] = SafeText(row["mnum"].upper().strip()) h, m, _ = row["duration"].split(":") row["duration"] = timedelta(hours=float(h), minutes=float(m)) super().before_import_row(row, **kwargs) class Meta: model = MissionProfile skip_unchanged = True report_skipped = True fields = ("mtype", "mnum", "duration",) import_id_fields = ("mtype", "mnum",) # Form class to assing aircrafts to students class ChangeAircraftForm(AdminActionForm): aircrafts = TypedMultipleChoiceField(choices=AircraftTypes) class MissionProfileAdmin(ImportMixin, AdminActionFormsMixin, admin.ModelAdmin): list_display = ("mtype", "mnum", "assigned_aircrafts", "duration", "notes", ) list_filter = ("mtype", ) actions = ("assign_aircraft", ) resource_classes = [MissionProfileResource] tmp_storage_class = CacheStorage skip_admin_log = True def get_queryset(self, request: HttpRequest) -> QuerySet[MissionProfile]: return super().get_queryset(request).order_by("mtype", "mnum") @action_with_form(ChangeAircraftForm, description="Assign Aircraft Type") def assign_aircraft(self, request: HttpRequest, queryset: QuerySet[MissionProfile], data: Dict[str, List[AircraftTypes]]): i: int ac_types: List[str] i, ac_types = assign_aircraft(queryset=queryset, data=data) messages.success(request, f"{i} Missions updated to {ac_types}") @admin.display(description="Assigned Aircrafts") def assigned_aircrafts(self, obj: MissionProfile) -> SafeText: if not obj.aircrafts: return SafeText("") return SafeText("/".join(ac.markings for ac in obj.aircrafts.all()))