from django.forms import TypedMultipleChoiceField from django.db.models.query import QuerySet from django.http import HttpRequest from django.contrib import admin, messages 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.instructors import Instructor from ..models.aircrafts import AircraftTypes from ..models.missions import MissionTypes from ..actions.assign_profile import assign_profile from ..actions.assign_aircraft import assign_aircraft from typing import Dict, List # Resource Class for Instructor data import class InstructorResource(ModelResource): surname = fields.Field(attribute="surname", column_name="surname") name = fields.Field(attribute="name", column_name="name") email = fields.Field(attribute="email", column_name="email") phone = fields.Field(attribute="phone", column_name="phone") # Cleanup fields before entering def before_import_row(self, row: Dict[str, str], **kwargs) -> None: row["name"] = SafeText("-".join(c.capitalize() for c in row["name"].split(" ")).strip()) row["surname"] = SafeText("-".join(c.capitalize() for c in row["surname"].split(" ")).strip()) row["phone"] = SafeText(row["phone"].replace(" ","")) row["email"] = SafeText(row["email"].lower().strip()) return super().before_import_row(row, **kwargs) class Meta: model = Instructor skip_unchanged = True report_skipped = True fields = ("surname", "name", "email", "phone", ) import_id_fields = ("surname", "name", ) # Form class to assing aircrafts to instructors class AssignMissionForm(AdminActionForm): mission_profiles = TypedMultipleChoiceField(choices=MissionTypes) # Form class to assing aircrafts to instructors class AssignAircraftForm(AdminActionForm): aircrafts = TypedMultipleChoiceField(choices=AircraftTypes) class InstructorAdmin(ImportMixin, AdminActionFormsMixin, admin.ModelAdmin): model = Instructor list_display = ("surname", "name", "email", "phone", "assigned_profiles", "assigned_aircrafts", "active", ) search_fields = ("surname", "name", "phone", "email", ) readonly_fields = ("username", "password", ) actions = ("assign_aircraft", "assign_profile", ) resource_classes = [InstructorResource] tmp_storage_class = CacheStorage skip_admin_log = True @admin.display(description="Password") def password(self, obj: Instructor) -> SafeText: return SafeText(obj.default_password()) @admin.display(description="Username") def username(self, obj: Instructor) -> SafeText: return SafeText(obj.default_username()) @admin.display(description="Assigned Profiles") def assigned_profiles(self, obj: Instructor) -> SafeText: if not obj.aircrafts: return SafeText("") return SafeText("/".join(mix.mtype for mix in obj.missions.distinct("mtype").order_by("mtype").all())) @admin.display(description="Assigned Aircrafts") def assigned_aircrafts(self, obj: Instructor) -> SafeText: if not obj.aircrafts: return SafeText("") return SafeText("/".join(ac.type for ac in obj.aircrafts.distinct("type").order_by("type").all())) @action_with_form(AssignAircraftForm, description="Assign Aircraft Type") def assign_aircraft(self, request: HttpRequest, queryset: QuerySet[Instructor], 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} Instructors updated to {ac_types}") @action_with_form(AssignMissionForm, description="Assign Mission Type") def assign_profile(self, request: HttpRequest, queryset: QuerySet[Instructor], data: Dict[str, List[MissionTypes]]): i: int mix_types: List[str] i, mix_types = assign_profile(queryset=queryset, data=data) messages.success(request, f"{i} Instructors updated to {mix_types}")