Admin files refactoring

This commit is contained in:
2025-11-18 22:44:16 +01:00
parent edb54e9f6f
commit 79d7333ca0
8 changed files with 319 additions and 276 deletions

View File

@@ -1,282 +1,14 @@
from django import forms
from django.db.models.query import QuerySet
from django.http import HttpRequest, HttpResponse
from django.contrib import admin, messages
from django.utils.translation import ngettext
from django.utils.safestring import SafeText
import nested_admin
from durationwidget.widgets import TimeDurationWidget
from import_export import fields
from import_export.admin import ImportMixin
from import_export.resources import ModelResource
from import_export.widgets import CharWidget
from django_admin_action_forms import AdminActionFormsMixin, AdminActionForm, action_with_form
from django.contrib import admin
from .models.courses import Course
from .models.hourbuildings import HourBuilding, HourBuildingLeg
from .models.missions import Training, MissionProfile
from .models.students import Student
from .models.missions import MissionProfile
from .models.weekpref import WeekPreference
from .custom.colortag import course_color
from .actions.exportweek import export_selected
from datetime import date
class TrainingForm(forms.ModelForm):
model=Training
class HourBuildingLegForm(forms.ModelForm):
class Meta:
model = HourBuildingLeg
fields = '__all__'
widgets = {
'time': TimeDurationWidget(show_days=False,
show_seconds=False
)
}
# Register your models here.
class HourBuildingLegInline(nested_admin.NestedTabularInline):
model = HourBuildingLeg
form = HourBuildingLegForm
extra = 0
fk_name = 'hb'
max_num = 5
# If user is a student deny edit permission for week past the current one
def has_change_permission(self, request: HttpRequest, obj: HourBuilding | None = None):
if hasattr(request.user, 'student') and obj:
current_week = date.today().isocalendar().week
if not obj.DoesNotExist and current_week > obj.weekpref.week:
return False
return True
def has_delete_permission(self, request: HttpRequest, obj: HourBuilding | None = None):
return self.has_change_permission(request=request, obj=obj)
class HourBuildingInLine(nested_admin.NestedTabularInline):
model = HourBuilding
extra = 0
inlines = [HourBuildingLegInline]
fk_name = 'weekpref'
verbose_name_plural = "Hour Building"
max_num = 7
# If user is a student deny edit permission for week past the current one
def has_change_permission(self, request: HttpRequest, obj: WeekPreference | None = None):
if hasattr(request.user, 'student') and obj:
current_week = date.today().isocalendar().week
if current_week > obj.week:
return False
return True
def has_delete_permission(self, request: HttpRequest, obj: WeekPreference | None = None):
return self.has_change_permission(request=request, obj=obj)
class TrainingInLIne(nested_admin.NestedTabularInline):
model = Training
form = TrainingForm
extra = 0
fk_name = 'weekpref'
verbose_name_plural = "Training Missions"
max_num = 7
# If user is a student deny edit permission for week past the current one
def has_change_permission(self, request: HttpRequest, obj: WeekPreference | None = None):
if hasattr(request.user, 'student') and obj:
current_week = date.today().isocalendar().week
if current_week > obj.week:
return False
return True
def has_delete_permission(self, request: HttpRequest, obj: WeekPreference | None = None):
return self.has_change_permission(request=request, obj=obj)
class WeekPreferenceAdmin(nested_admin.NestedModelAdmin):
inlines = (TrainingInLIne, HourBuildingInLine,)
list_display = ("week", "student__surname","student__name", "student__course", "course_color", "student_brief_mix",)
list_filter = ("week", "student__course", "student",)
actions = ("export",)
@admin.action(description="Export Selected Preferences")
def export(weekpreferenceadmin, request: HttpRequest, queryset: QuerySet[WeekPreference]) -> HttpResponse | None:
if queryset.count() == 0:
return None
weekpreferenceadmin.message_user(request, ngettext("Exporting %d row", "Exporting %d rows", queryset.count()) % queryset.count(), messages.SUCCESS)
return export_selected(request=request, queryset=queryset)
@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)
# If a user is registered as student hide filters
def get_list_filter(self, request):
list_filter = super().get_list_filter(request)
if hasattr(request.user, 'student'):
return []
return list_filter
# If a user is registered as student do not show actions
def get_actions(self, request):
actions = super().get_actions(request)
if hasattr(request.user, 'student'):
return []
return actions
# If a user is registered as student show only their preferences
def get_queryset(self, request):
qs = super().get_queryset(request)
if hasattr(request.user, 'student'):
return qs.filter(student=request.user.student)
# If admin show everything
return qs
def get_form(self, request, obj=None, **kwargs):
form: forms.Form = super().get_form(request, obj, **kwargs)
current_week = date.today().isocalendar().week
# If form contains the week field
if 'week' in form.base_fields:
# Set default value as current week
form.base_fields['week'].initial = current_week
# If student is current user making request
if hasattr(request.user, 'student'):
student = request.user.student
if 'student' in form.base_fields:
form.base_fields['student'].initial = student
form.base_fields['student'].disabled = True
form.base_fields['week'].disabled = True # student cannot change week
return form
# If user is a student deny edit permission for week past the current one
def has_change_permission(self, request, obj: WeekPreference | None = None):
if hasattr(request.user, 'student') and obj:
current_week = date.today().isocalendar().week
if current_week > obj.week:
return False
return True
# If user is a student deny edit permission for week past the current one
def has_add_permission(self, request, obj: WeekPreference | None = None):
if hasattr(request.user, 'student') and obj:
current_week = date.today().isocalendar().week
if current_week > obj.week:
return False
return True
# If user is a student deny edit permission for week past the current one
def has_delete_permission(self, request, obj: WeekPreference | None = None):
if hasattr(request.user, 'student') and obj:
current_week = date.today().isocalendar().week
if current_week > obj.week:
return False
return True
def changeform_view(self, request: HttpRequest, object_id: int | None = None, form_url: str = '', extra_context=None):
extra_context = extra_context or {}
if hasattr(request.user, 'student') and object_id:
current_week = date.today().isocalendar().week
weekpref = WeekPreference.objects.get(id=object_id)
if current_week > weekpref.week:
extra_context['show_save'] = False
extra_context['show_save_and_continue'] = False
extra_context['show_save_and_add_another'] = False
extra_context['show_delete'] = False
return super().changeform_view(request, object_id, form_url, extra_context)
def save_model(self, request, obj, form, change):
# Imposta automaticamente lo studente se non è già valorizzato
if hasattr(request.user, 'student') and not obj.student_id:
obj.student = request.user.student
super().save_model(request, obj, form, change)
# Resource Class for Student data import
class StudentResource(ModelResource):
surname = fields.Field(attribute="surname", column_name="surname", widget=CharWidget())
name = fields.Field(attribute="name", column_name="name", widget=CharWidget())
email = fields.Field(attribute="email", column_name="email", widget=CharWidget())
phone = fields.Field(attribute="phone", column_name="phone", widget=CharWidget())
# Cleanup fields before entering
def before_import_row(self, row: dict[str, str], **kwargs) -> None:
row['name'] = SafeText(row['name'].capitalize().strip())
row['surname'] = SafeText(row['surname'].capitalize().strip())
row['phone'] = SafeText(row['phone'].replace(' ',''))
row['email'] = SafeText(row['email'].lower().strip())
return super().before_import_row(row, **kwargs)
class Meta:
model = Student
skip_unchanged = True
report_skipped = True
fields = ('surname', 'name', 'email', 'phone')
import_id_fields = ['email', 'phone']
# Form Class for Student course change
class ChangeCourseForm(AdminActionForm):
course = forms.ModelChoiceField(queryset=Course.objects.all())
class StudentAdmin(ImportMixin, AdminActionFormsMixin, admin.ModelAdmin):
list_display = ("surname", "name", "course", "course_color", "email", "phone", "password", "active")
list_filter = ("course", "active")
actions = ("change_course", "disable_students")
resource_classes = [StudentResource]
@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(obj.default_password())
@admin.action(description="Disable Students")
def disable_students(self, request: HttpRequest, queryset: QuerySet[Student]):
for q in queryset.all():
if q.user:
q.user.is_staff = False
q.user.save()
count: int = queryset.update(active = False)
messages.success(request, f"{count} students deactivated")
pass
@action_with_form(ChangeCourseForm, description="Change Student Course")
def change_course(self, request: HttpRequest, queryset: QuerySet[Student], data):
course = data["course"]
count: int = queryset.update(course=course)
messages.success(request, f"{count} students updated to {course}")
class CourseAdmin(admin.ModelAdmin):
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_filter = ("mtype",)
from .admins.course_adm import CourseAdmin
from .admins.student_adm import StudentAdmin
from .admins.mission_adm import MissionProfileAdmin
from .admins.weekpred_adm import WeekPreferenceAdmin
admin.site.register(Course, CourseAdmin)
admin.site.register(MissionProfile, MissionProfileAdmin)

View File

@@ -0,0 +1,16 @@
from django.contrib import admin
from django.utils.safestring import SafeText
from ..models.courses import Course
from ..custom.colortag import course_color
class CourseAdmin(admin.ModelAdmin):
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)

View File

@@ -0,0 +1,59 @@
import nested_admin
from django import forms
from django.http import HttpRequest
from durationwidget.widgets import TimeDurationWidget
from ..models.hourbuildings import HourBuilding, HourBuildingLeg
from ..models.weekpref import WeekPreference
from datetime import date
class HourBuildingLegForm(forms.ModelForm):
class Meta:
model = HourBuildingLeg
fields = '__all__'
widgets = {
'time': TimeDurationWidget(show_days=False,
show_seconds=False
)
}
# Register your models here.
class HourBuildingLegInline(nested_admin.NestedTabularInline):
model = HourBuildingLeg
form = HourBuildingLegForm
extra = 0
fk_name = 'hb'
max_num = 5
# If user is a student deny edit permission for week past the current one
def has_change_permission(self, request: HttpRequest, obj: HourBuilding | None = None):
if hasattr(request.user, 'student') and obj:
current_week = date.today().isocalendar().week
if not obj.DoesNotExist and current_week > obj.weekpref.week:
return False
return True
def has_delete_permission(self, request: HttpRequest, obj: HourBuilding | None = None):
return self.has_change_permission(request=request, obj=obj)
class HourBuildingInLine(nested_admin.NestedTabularInline):
model = HourBuilding
extra = 0
inlines = [HourBuildingLegInline]
fk_name = 'weekpref'
verbose_name_plural = "Hour Building"
max_num = 7
# If user is a student deny edit permission for week past the current one
def has_change_permission(self, request: HttpRequest, obj: WeekPreference | None = None):
if hasattr(request.user, 'student') and obj:
current_week = date.today().isocalendar().week
if current_week > obj.week:
return False
return True
def has_delete_permission(self, request: HttpRequest, obj: WeekPreference | None = None):
return self.has_change_permission(request=request, obj=obj)

View File

@@ -0,0 +1,5 @@
from django.contrib import admin
class MissionProfileAdmin(admin.ModelAdmin):
list_display = ("mtype", "mnum",)
list_filter = ("mtype",)

View File

@@ -0,0 +1,75 @@
from django import forms
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 import_export import fields
from import_export.admin import ImportMixin
from import_export.resources import ModelResource
from import_export.widgets import CharWidget
from django_admin_action_forms import AdminActionFormsMixin, AdminActionForm, action_with_form
from ..models.courses import Course
from ..models.students import Student
from ..custom.colortag import course_color
# Resource Class for Student data import
class StudentResource(ModelResource):
surname = fields.Field(attribute="surname", column_name="surname", widget=CharWidget())
name = fields.Field(attribute="name", column_name="name", widget=CharWidget())
email = fields.Field(attribute="email", column_name="email", widget=CharWidget())
phone = fields.Field(attribute="phone", column_name="phone", widget=CharWidget())
# Cleanup fields before entering
def before_import_row(self, row: dict[str, str], **kwargs) -> None:
row["name"] = SafeText(row["name"].capitalize().strip())
row["surname"] = SafeText(row["surname"].capitalize().strip())
row["phone"] = SafeText(row["phone"].replace(" ",""))
row["email"] = SafeText(row["email"].lower().strip())
return super().before_import_row(row, **kwargs)
class Meta:
model = Student
skip_unchanged = True
report_skipped = True
fields = ("surname", "name", "email", "phone")
import_id_fields = ("email", "phone")
# Form Class for Student course change
class ChangeCourseForm(AdminActionForm):
course = forms.ModelChoiceField(queryset=Course.objects.all())
class StudentAdmin(ImportMixin, AdminActionFormsMixin, admin.ModelAdmin):
list_display = ("surname", "name", "course", "course_color", "email", "phone", "password", "active")
list_filter = ("course", "active")
actions = ("change_course", "disable_students")
resource_classes = [StudentResource]
@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(obj.default_password())
@admin.action(description="Disable Students")
def disable_students(self, request: HttpRequest, queryset: QuerySet[Student]):
for q in queryset.all():
if q.user:
q.user.is_staff = False
q.user.save()
count: int = queryset.update(active = False)
messages.success(request, f"{count} students deactivated")
pass
@action_with_form(ChangeCourseForm, description="Change Student Course")
def change_course(self, request: HttpRequest, queryset: QuerySet[Student], data):
course = data["course"]
count: int = queryset.update(course=course)
messages.success(request, f"{count} students updated to {course}")

View File

@@ -0,0 +1,30 @@
import nested_admin
from django import forms
from django.http import HttpRequest
from ..models.missions import Training
from ..models.weekpref import WeekPreference
from datetime import date
class TrainingForm(forms.ModelForm):
model=Training
class TrainingInLIne(nested_admin.NestedTabularInline):
model = Training
form = TrainingForm
extra = 0
fk_name = 'weekpref'
verbose_name_plural = "Training Missions"
max_num = 7
# If user is a student deny edit permission for week past the current one
def has_change_permission(self, request: HttpRequest, obj: WeekPreference | None = None):
if hasattr(request.user, 'student') and obj:
current_week: int = date.today().isocalendar().week
if current_week > obj.week:
return False
return True
def has_delete_permission(self, request: HttpRequest, obj: WeekPreference | None = None):
return self.has_change_permission(request=request, obj=obj)

View File

@@ -0,0 +1,126 @@
import nested_admin
from django import forms
from django.db.models.query import QuerySet
from django.http import HttpRequest, HttpResponse
from django.contrib import admin, messages
from django.utils.translation import ngettext
from django.utils.safestring import SafeText
from ..models.missions import Training
from ..models.weekpref import WeekPreference
from .training_adm import TrainingInLIne
from .hourbuilding_adm import HourBuildingInLine
from ..custom.colortag import course_color
from ..actions.exportweek import export_selected
from datetime import date
class WeekPreferenceAdmin(nested_admin.NestedModelAdmin):
inlines = (TrainingInLIne, HourBuildingInLine,)
list_display = ("week", "student__surname","student__name", "student__course", "course_color", "student_brief_mix",)
list_filter = ("week", "student__course", "student",)
actions = ("export",)
@admin.action(description="Export Selected Preferences")
def export(self, request: HttpRequest, queryset: QuerySet[WeekPreference]) -> HttpResponse | None:
if queryset.count() == 0:
return None
self.message_user(request, ngettext("Exporting %d row", "Exporting %d rows", queryset.count()) % queryset.count(), messages.SUCCESS)
return export_selected(request=request, queryset=queryset)
@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)
# If a user is registered as student hide filters
def get_list_filter(self, request):
list_filter = super().get_list_filter(request)
if hasattr(request.user, 'student'):
return []
return list_filter
# If a user is registered as student do not show actions
def get_actions(self, request):
actions = super().get_actions(request)
if hasattr(request.user, 'student'):
return []
return actions
# If a user is registered as student show only their preferences
def get_queryset(self, request):
qs = super().get_queryset(request)
if hasattr(request.user, 'student'):
return qs.filter(student=request.user.student)
# If admin show everything
return qs
def get_form(self, request, obj=None, **kwargs):
form: forms.Form = super().get_form(request, obj, **kwargs)
current_week = date.today().isocalendar().week
# If form contains the week field
if 'week' in form.base_fields:
# Set default value as current week
form.base_fields['week'].initial = current_week
# If student is current user making request
if hasattr(request.user, 'student'):
student = request.user.student
if 'student' in form.base_fields:
form.base_fields['student'].initial = student
form.base_fields['student'].disabled = True
form.base_fields['week'].disabled = True # student cannot change week
return form
# If user is a student deny edit permission for week past the current one
def has_change_permission(self, request, obj: WeekPreference | None = None):
if hasattr(request.user, 'student') and obj:
current_week = date.today().isocalendar().week
if current_week > obj.week:
return False
return True
# If user is a student deny edit permission for week past the current one
def has_add_permission(self, request, obj: WeekPreference | None = None):
if hasattr(request.user, 'student') and obj:
current_week = date.today().isocalendar().week
if current_week > obj.week:
return False
return True
# If user is a student deny edit permission for week past the current one
def has_delete_permission(self, request, obj: WeekPreference | None = None):
if hasattr(request.user, 'student') and obj:
current_week = date.today().isocalendar().week
if current_week > obj.week:
return False
return True
def changeform_view(self, request: HttpRequest, object_id: int | None = None, form_url: str = '', extra_context=None):
extra_context = extra_context or {}
if hasattr(request.user, 'student') and object_id:
current_week = date.today().isocalendar().week
weekpref = WeekPreference.objects.get(id=object_id)
if current_week > weekpref.week:
extra_context['show_save'] = False
extra_context['show_save_and_continue'] = False
extra_context['show_save_and_add_another'] = False
extra_context['show_delete'] = False
return super().changeform_view(request, object_id, form_url, extra_context)
def save_model(self, request, obj, form, change):
# Imposta automaticamente lo studente se non è già valorizzato
if hasattr(request.user, 'student') and not obj.student_id:
obj.student = request.user.student
super().save_model(request, obj, form, change)

View File

@@ -47,10 +47,10 @@ INSTALLED_APPS = [
]
# Import Export plugin settings
from import_export.formats.base_formats import CSV
IMPORT_EXPORT_USE_TRANSACTIONS = True
IMPORT_EXPORT_SKIP_ADMIN_LOG = True
from import_export.formats.base_formats import CSV, XLSX
IMPORT_FORMATS = [CSV, XLSX]
IMPORT_FORMATS = [CSV]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',