Demo export action and added color badges where needed

This commit is contained in:
2025-11-14 15:47:18 +01:00
parent be25a07272
commit bb9ff3a86c
6 changed files with 145 additions and 25 deletions

View File

@@ -1,8 +1,13 @@
from django import forms from django import forms
from django.db.models.query import QuerySet
from django.contrib import admin from django.contrib import admin
from django.http import HttpRequest, HttpResponse
from django.utils.safestring import SafeText
from durationwidget.widgets import TimeDurationWidget from durationwidget.widgets import TimeDurationWidget
from datetime import date from datetime import date
import nested_admin import nested_admin
import csv
from .models.courses import Course from .models.courses import Course
from .models.hourbuildings import HourBuilding, HourBuildingLeg from .models.hourbuildings import HourBuilding, HourBuildingLeg
@@ -10,6 +15,9 @@ from .models.missions import Training, MissionProfile
from .models.students import Student from .models.students import Student
from .models.weekpref import WeekPreference from .models.weekpref import WeekPreference
from .custom.colortag import course_color
from .custom.defpassword import default_password
class TrainingForm(forms.ModelForm): class TrainingForm(forms.ModelForm):
model=Training model=Training
@@ -49,7 +57,43 @@ class TrainingInLIne(nested_admin.NestedTabularInline):
class WeekPreferenceAdmin(nested_admin.NestedModelAdmin): class WeekPreferenceAdmin(nested_admin.NestedModelAdmin):
inlines = [TrainingInLIne, HourBuildingInLine] inlines = [TrainingInLIne, HourBuildingInLine]
list_filter = ["week", "student__course", "student"] list_display = ("week", "student__name", "student__surname", "student__course", "course_color", "student_brief_mix")
list_filter = ("week", "student__course", "student")
actions = ("export_selected",)
@admin.action(description="Export Selected Preferences")
def export_selected(modeladmin, request: HttpRequest, queryset: QuerySet[WeekPreference]) -> HttpResponse:
filename = "weekpreferences_export.csv"
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = f'attachment; filename="{filename}"'
writer = csv.writer(response)
# intestazione — scegli i campi che vuoi esportare
writer.writerow(['student_name', 'student_surname', 'course', 'course_color', "training", "hourbuilding"])
for q in queryset:
writer.writerow([
q.student.name,
q.student.surname,
q.student.course,
q.student.course.color,
"+".join([f"{t.mission.mtype}-{t.mission.mnum}" for t in Training.objects.filter(weekpref = q.id)]),
"+".join([f"HB_{t.aircraft}" for t in HourBuilding.objects.filter(weekpref = q.id)]),
])
return response
@admin.display(description="Mission Count")
def student_brief_mix(self, obj: WeekPreference) -> SafeText:
if not obj.student.course:
return SafeText("")
return SafeText(f"{Training.objects.filter(weekpref = obj.id).count()}")
@admin.display(description="Color")
def course_color(self, obj: WeekPreference) -> SafeText:
if not obj.student.course:
return SafeText("")
return course_color(obj.student.course.color)
def has_module_permission(self, request): def has_module_permission(self, request):
if hasattr(request.user, 'student'): if hasattr(request.user, 'student'):
@@ -73,13 +117,13 @@ class WeekPreferenceAdmin(nested_admin.NestedModelAdmin):
if 'student' in form.base_fields: if 'student' in form.base_fields:
form.base_fields['student'].initial = student form.base_fields['student'].initial = student
form.base_fields['student'].disabled = True form.base_fields['student'].disabled = True
form.base_fields['week'].disabled = True
# If form contains the week field # If form contains the week field
if 'week' in form.base_fields: if 'week' in form.base_fields:
# Set default value as current week # Set default value as current week
current_week = date.today().isocalendar().week current_week = date.today().isocalendar().week
form.base_fields['week'].initial = current_week form.base_fields['week'].initial = current_week
form.base_fields['week'].disabled = True
return form return form
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
@@ -89,22 +133,41 @@ class WeekPreferenceAdmin(nested_admin.NestedModelAdmin):
super().save_model(request, obj, form, change) super().save_model(request, obj, form, change)
class StudentAdmin(admin.ModelAdmin): class StudentAdmin(admin.ModelAdmin):
list_display = ("surname", "name", "course", "email","active") list_display = ("surname", "name", "course", "course_color", "email", "phone", "password", "active")
list_filter = ["course", "active"] list_filter = ("course", "active")
actions = ("disable_students",)
class CourseAdminForm(forms.ModelForm): @admin.display(description="Color")
class Meta: def course_color(self, obj: Student) -> SafeText:
model = Course if not obj.course:
return SafeText("")
return course_color(obj.course.color)
@admin.display(description="Password")
def password(self, obj: Student) -> SafeText:
return SafeText(default_password(student=obj))
@admin.action(description="Disable Students")
def disable_students(modeladmin, request: HttpRequest, queryset: QuerySet[Student]):
queryset.update(active = False)
pass
class CourseAdmin(admin.ModelAdmin): class CourseAdmin(admin.ModelAdmin):
list_display = ["ctype", "cnumber", "year", "color"] list_display = ("ctype", "cnumber","color_display", "year")
list_filter = ["ctype", "year"] list_filter = ("ctype", "year")
form=CourseAdminForm
# Dinamically add color_display property to show a colored dot
@admin.display(description="Color")
def color_display(self, obj: Course) -> SafeText:
if not obj.pk:
return SafeText("")
return course_color(obj.color)
class MissionProfileAdmin(admin.ModelAdmin): class MissionProfileAdmin(admin.ModelAdmin):
list_display = ("mtype", "mnum") list_display = ("mtype", "mnum",)
list_filter = ("mtype",)
admin.site.register(Course, CourseAdmin) admin.site.register(Course, CourseAdmin)
admin.site.register(MissionProfile) admin.site.register(MissionProfile, MissionProfileAdmin)
admin.site.register(Student, StudentAdmin) admin.site.register(Student, StudentAdmin)
admin.site.register(WeekPreference, WeekPreferenceAdmin) admin.site.register(WeekPreference, WeekPreferenceAdmin)

View File

@@ -0,0 +1,18 @@
from colorfield.fields import ColorField
from django.utils.html import format_html
from django.utils.safestring import SafeText
def course_color(color: ColorField | None) -> SafeText:
if not color:
return format_html("")
return format_html(
'<div style="background-color: {}; \
width: 20px; height: 20px; \
border-radius: 25%; \
border-color: gray; \
border-style: solid; \
border-width: 1px; \
display: inline-block; \
"></div>',
color
)

View File

@@ -0,0 +1,4 @@
from ..models.students import Student
def default_password(student: Student) -> str:
return f"{student.name.lower()[0]}{student.surname.lower()}{student.id}"

View File

@@ -0,0 +1,39 @@
# Generated by Django 5.2.8 on 2025-11-14 14:42
import colorfield.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0015_alter_course_color'),
]
operations = [
migrations.AlterField(
model_name='course',
name='cnumber',
field=models.PositiveSmallIntegerField(default=2025, verbose_name='Course Number'),
),
migrations.AlterField(
model_name='course',
name='color',
field=colorfield.fields.ColorField(default='#FFFFFF', image_field=None, max_length=25, samples=[('#ffffff', 'WHITE'), ('#ff0000', 'RED'), ('#00ff00', 'GREEN'), ('#0000ff', 'BLUE')], verbose_name='Binder Color'),
),
migrations.AlterField(
model_name='course',
name='ctype',
field=models.CharField(choices=[('FI', 'FI'), ('PPL', 'PPL'), ('ATPL', 'ATPL'), ('DL', 'DISTANCE'), ('OTHER', 'OTHER')], verbose_name='Course Type'),
),
migrations.AlterField(
model_name='course',
name='year',
field=models.PositiveSmallIntegerField(default=2025, verbose_name='Year'),
),
migrations.AlterField(
model_name='hourbuilding',
name='aircraft',
field=models.CharField(choices=[('C152', 'Cessna 152'), ('P208', 'Tecnam P2008'), ('PA28', 'Piper PA28R'), ('C182', 'Cessna 182Q'), ('TWEN', 'Tecnam P2010')]),
),
]

View File

@@ -6,4 +6,4 @@ class AircraftTypes(models.TextChoices):
P208 = "P208", _("Tecnam P2008") P208 = "P208", _("Tecnam P2008")
PA28 = "PA28", _("Piper PA28R") PA28 = "PA28", _("Piper PA28R")
C182 = "C182", _("Cessna 182Q") C182 = "C182", _("Cessna 182Q")
P210 = "P210", _("Tecnam P2010") P210 = "TWEN", _("Tecnam P2010")

View File

@@ -3,32 +3,28 @@ from django.dispatch import receiver
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from .models.students import Student from .models.students import Student
from .custom.defpassword import default_password
# Create a Django user every time a new student is created # Create a Django user every time a new student is created
@receiver(post_save, sender=Student) @receiver(post_save, sender=Student)
def create_user_for_student(sender: Student, instance: Student, created, **kwargs): def create_user_for_student(sender: Student, student: Student, created, **kwargs):
if created and not instance.user: if created and not student.user:
print("_____ SAVING USER _____") username = f"{student.name.lower()}.{student.surname.lower()}"
username = f"{instance.name.lower()}.{instance.surname.lower()}"
# Avoid username conflict with progressive number # Avoid username conflict with progressive number
base_username = username base_username = username
counter = 1 counter = 1
while User.objects.filter(username=username).exists(): while User.objects.filter(username=username).exists():
username = f"{base_username}{counter}" username = f"{base_username}{counter}"
counter += 1 counter += 1
# Generate standard password for every student
password = f"{instance.name.lower()[0]}{instance.surname.lower()}{instance.id}"
# Create user # Create user
user = User.objects.create_user( user = User.objects.create_user(
username=username, username=username,
email=instance.email, email=student.email,
password=password password=default_password(student=student)
) )
student_group, _ = Group.objects.get_or_create(name="StudentGroup") student_group, _ = Group.objects.get_or_create(name="StudentGroup")
user.groups.add(student_group) user.groups.add(student_group)
student.user = user
print(f"User: {user.username}\tPassword: {password}") student.save()
instance.user = user
instance.save()