Demo export action and added color badges where needed
This commit is contained in:
@@ -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)
|
||||
|
||||
18
techdb/flightslot/custom/colortag.py
Normal file
18
techdb/flightslot/custom/colortag.py
Normal 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
|
||||
)
|
||||
4
techdb/flightslot/custom/defpassword.py
Normal file
4
techdb/flightslot/custom/defpassword.py
Normal 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}"
|
||||
@@ -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')]),
|
||||
),
|
||||
]
|
||||
@@ -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")
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user