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.db.models.query import QuerySet
from django.contrib import admin
from django.http import HttpRequest, HttpResponse
from django.utils.safestring import SafeText
from durationwidget.widgets import TimeDurationWidget
from datetime import date
import nested_admin
import csv
from .models.courses import Course
from .models.hourbuildings import HourBuilding, HourBuildingLeg
@@ -10,6 +15,9 @@ from .models.missions import Training, MissionProfile
from .models.students import Student
from .models.weekpref import WeekPreference
from .custom.colortag import course_color
from .custom.defpassword import default_password
class TrainingForm(forms.ModelForm):
model=Training
@@ -49,7 +57,43 @@ class TrainingInLIne(nested_admin.NestedTabularInline):
class WeekPreferenceAdmin(nested_admin.NestedModelAdmin):
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):
if hasattr(request.user, 'student'):
@@ -73,13 +117,13 @@ class WeekPreferenceAdmin(nested_admin.NestedModelAdmin):
if 'student' in form.base_fields:
form.base_fields['student'].initial = student
form.base_fields['student'].disabled = True
form.base_fields['week'].disabled = True
# If form contains the week field
if 'week' in form.base_fields:
# Set default value as current week
current_week = date.today().isocalendar().week
form.base_fields['week'].initial = current_week
form.base_fields['week'].disabled = True
return form
def save_model(self, request, obj, form, change):
@@ -89,22 +133,41 @@ class WeekPreferenceAdmin(nested_admin.NestedModelAdmin):
super().save_model(request, obj, form, change)
class StudentAdmin(admin.ModelAdmin):
list_display = ("surname", "name", "course", "email","active")
list_filter = ["course", "active"]
list_display = ("surname", "name", "course", "course_color", "email", "phone", "password", "active")
list_filter = ("course", "active")
actions = ("disable_students",)
class CourseAdminForm(forms.ModelForm):
class Meta:
model = Course
@admin.display(description="Color")
def course_color(self, obj: Student) -> SafeText:
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):
list_display = ["ctype", "cnumber", "year", "color"]
list_filter = ["ctype", "year"]
form=CourseAdminForm
list_display = ("ctype", "cnumber","color_display", "year")
list_filter = ("ctype", "year")
# 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):
list_display = ("mtype", "mnum")
list_display = ("mtype", "mnum",)
list_filter = ("mtype",)
admin.site.register(Course, CourseAdmin)
admin.site.register(MissionProfile)
admin.site.register(MissionProfile, MissionProfileAdmin)
admin.site.register(Student, StudentAdmin)
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")
PA28 = "PA28", _("Piper PA28R")
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 Group
from .models.students import Student
from .custom.defpassword import default_password
# Create a Django user every time a new student is created
@receiver(post_save, sender=Student)
def create_user_for_student(sender: Student, instance: Student, created, **kwargs):
if created and not instance.user:
print("_____ SAVING USER _____")
username = f"{instance.name.lower()}.{instance.surname.lower()}"
def create_user_for_student(sender: Student, student: Student, created, **kwargs):
if created and not student.user:
username = f"{student.name.lower()}.{student.surname.lower()}"
# Avoid username conflict with progressive number
base_username = username
counter = 1
while User.objects.filter(username=username).exists():
username = f"{base_username}{counter}"
counter += 1
# Generate standard password for every student
password = f"{instance.name.lower()[0]}{instance.surname.lower()}{instance.id}"
# Create user
user = User.objects.create_user(
username=username,
email=instance.email,
password=password
email=student.email,
password=default_password(student=student)
)
student_group, _ = Group.objects.get_or_create(name="StudentGroup")
user.groups.add(student_group)
print(f"User: {user.username}\tPassword: {password}")
instance.user = user
instance.save()
student.user = user
student.save()