8 Commits

38 changed files with 1476 additions and 90 deletions

18
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,18 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python Debugger: Django",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/techdb/manage.py",
"args": ["runserver"],
"console": "integratedTerminal",
"django": true,
"justMyCode": false
}
]
}

View File

173
techdb/flightslot/admin.py Normal file
View File

@@ -0,0 +1,173 @@
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
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
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
class HourBuildingInLine(nested_admin.NestedTabularInline):
model = HourBuilding
extra = 0
inlines = [HourBuildingLegInline]
fk_name = 'weekpref'
verbose_name_plural = "Hour Building"
max_num = 7
class TrainingInLIne(nested_admin.NestedTabularInline):
model = Training
form = TrainingForm
extra = 0
fk_name = 'weekpref'
verbose_name_plural = "Training Missions"
max_num = 7
class WeekPreferenceAdmin(nested_admin.NestedModelAdmin):
inlines = [TrainingInLIne, HourBuildingInLine]
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'):
return False
return True
def get_queryset(self, request):
qs = super().get_queryset(request)
# If a user is registered as student show only their preferences
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)
# 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
# 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
return form
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)
class StudentAdmin(admin.ModelAdmin):
list_display = ("surname", "name", "course", "course_color", "email", "phone", "password", "active")
list_filter = ("course", "active")
actions = ("disable_students",)
@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","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",)
admin.site.register(Course, CourseAdmin)
admin.site.register(MissionProfile, MissionProfileAdmin)
admin.site.register(Student, StudentAdmin)
admin.site.register(WeekPreference, WeekPreferenceAdmin)

View File

@@ -0,0 +1,9 @@
from django.apps import AppConfig
class FlightslotConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'flightslot'
def ready(self):
# Import only when application is ready otherwise signals will not be called
from . import signals

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,23 @@
# Generated by Django 5.1.2 on 2024-10-19 16:07
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Student',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('email', models.EmailField(db_index=True, max_length=254)),
('name', models.CharField(max_length=32)),
('surname', models.CharField(max_length=32)),
],
),
]

View File

@@ -0,0 +1,47 @@
# Generated by Django 5.1.2 on 2024-10-19 17:49
import django.db.models.deletion
import django.db.models.expressions
import django.db.models.functions.datetime
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='MissionProfile',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('mtype', models.IntegerField(choices=[('OTHER', 'OTHER'), ('HB', 'HB'), ('PPL', 'PPL'), ('IR', 'IR'), ('CPL', 'CPL'), ('FI', 'FI'), ('PC', 'PC'), ('CHK', 'CHK_6M')], default='HB')),
('mnum', models.PositiveSmallIntegerField(default=0, null=True)),
('duration', models.DurationField()),
],
),
migrations.CreateModel(
name='WeekPreference',
fields=[
('id', models.BigAutoField(primary_key=True, serialize=False)),
('week', models.PositiveSmallIntegerField(db_default=django.db.models.expressions.CombinedExpression(django.db.models.functions.datetime.ExtractWeek(django.db.models.functions.datetime.Now()), '+', models.Value(1)), db_index=True)),
('student', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='flightslot.student')),
],
),
migrations.CreateModel(
name='Preference',
fields=[
('id', models.BigAutoField(primary_key=True, serialize=False)),
('monday', models.BooleanField(default=True)),
('tuesday', models.BooleanField(default=True)),
('wednesday', models.BooleanField(default=True)),
('thursday', models.BooleanField(default=True)),
('saturday', models.BooleanField(default=True)),
('sunday', models.BooleanField(default=True)),
('mission', models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='flightslot.missionprofile')),
('weekpref', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='flightslot.weekpreference')),
],
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2024-10-19 17:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0002_missionprofile_weekpreference_preference'),
]
operations = [
migrations.AlterField(
model_name='missionprofile',
name='mtype',
field=models.CharField(choices=[('OTHER', 'OTHER'), ('HB', 'HB'), ('PPL', 'PPL'), ('IR', 'IR'), ('CPL', 'CPL'), ('FI', 'FI'), ('PC', 'PC'), ('CHK', 'CHK_6M')], default='HB'),
),
]

View File

@@ -0,0 +1,65 @@
# Generated by Django 5.1.2 on 2024-10-20 07:57
import django.db.models.deletion
import django.db.models.expressions
import django.db.models.functions.datetime
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0003_alter_missionprofile_mtype'),
]
operations = [
migrations.RenameModel(
old_name='Preference',
new_name='Training',
),
migrations.AddField(
model_name='missionprofile',
name='notes',
field=models.TextField(max_length=140, null=True),
),
migrations.AlterField(
model_name='missionprofile',
name='duration',
field=models.DurationField(default=1),
),
migrations.AlterField(
model_name='missionprofile',
name='mtype',
field=models.CharField(choices=[('OTHER', 'OTHER'), ('PPL', 'PPL'), ('IR', 'IR'), ('CPL', 'CPL'), ('FI', 'FI'), ('PC', 'PC'), ('CHK', 'CHK_6M')], default='PPL'),
),
migrations.AlterField(
model_name='weekpreference',
name='week',
field=models.PositiveSmallIntegerField(auto_created=True, db_index=True, default=django.db.models.expressions.CombinedExpression(django.db.models.functions.datetime.ExtractWeek(django.db.models.functions.datetime.Now()), '+', models.Value(1))),
),
migrations.CreateModel(
name='HourBuilding',
fields=[
('id', models.BigAutoField(primary_key=True, serialize=False)),
('aircraft', models.CharField(choices=[('C152', 'Cessna 152'), ('P208', 'Tecnam P2008'), ('PA28', 'Piper PA28R'), ('C182', 'Cessna 182Q'), ('P210', 'Tecnam P2010')])),
('monday', models.BooleanField(default=True)),
('tuesday', models.BooleanField(default=True)),
('wednesday', models.BooleanField(default=True)),
('thursday', models.BooleanField(default=True)),
('saturday', models.BooleanField(default=True)),
('sunday', models.BooleanField(default=True)),
('weekpref', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='flightslot.weekpreference')),
],
),
migrations.CreateModel(
name='HourBuildingLeg',
fields=[
('id', models.BigAutoField(primary_key=True, serialize=False)),
('departure', models.CharField(default='LILV', max_length=4)),
('destination', models.CharField(default='LILV', max_length=4)),
('time', models.DurationField(default=1)),
('stop', models.BooleanField(default=False)),
('hb', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='flightslot.hourbuilding')),
],
),
]

View File

@@ -0,0 +1,39 @@
# Generated by Django 5.1.2 on 2024-10-20 08:28
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0004_rename_preference_training_missionprofile_notes_and_more'),
]
operations = [
migrations.AddField(
model_name='hourbuilding',
name='notes',
field=models.TextField(max_length=140, null=True),
),
migrations.AddField(
model_name='training',
name='notes',
field=models.TextField(max_length=140, null=True),
),
migrations.AlterField(
model_name='hourbuilding',
name='weekpref',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='flightslot.weekpreference'),
),
migrations.AlterField(
model_name='training',
name='mission',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='flightslot.missionprofile'),
),
migrations.AlterField(
model_name='training',
name='weekpref',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='flightslot.weekpreference'),
),
]

View File

@@ -0,0 +1,33 @@
# Generated by Django 5.1.2 on 2024-10-20 09:14
import django.db.models.deletion
import django.db.models.functions.datetime
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0005_hourbuilding_notes_training_notes_and_more'),
]
operations = [
migrations.CreateModel(
name='Course',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('ctype', models.CharField(choices=[('PPL', 'PPL'), ('ATPL', 'ATPL')])),
('cnumber', models.PositiveSmallIntegerField(default=django.db.models.functions.datetime.ExtractYear(django.db.models.functions.datetime.Now()))),
],
),
migrations.AddField(
model_name='student',
name='active',
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name='student',
name='course',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='flightslot.course'),
),
]

View File

@@ -0,0 +1,34 @@
# Generated by Django 5.1.2 on 2024-10-20 09:27
import django.db.models.functions.datetime
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0006_course_student_active_student_course'),
]
operations = [
migrations.AddField(
model_name='course',
name='year',
field=models.PositiveSmallIntegerField(db_default=django.db.models.functions.datetime.ExtractYear(django.db.models.functions.datetime.Now()), editable=False),
),
migrations.AlterField(
model_name='hourbuilding',
name='notes',
field=models.TextField(blank=True, max_length=140, null=True),
),
migrations.AlterField(
model_name='missionprofile',
name='notes',
field=models.TextField(blank=True, max_length=140, null=True),
),
migrations.AlterField(
model_name='training',
name='notes',
field=models.TextField(blank=True, max_length=140, null=True),
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.1.2 on 2024-10-20 10:07
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0007_course_year_alter_hourbuilding_notes_and_more'),
]
operations = [
migrations.AddField(
model_name='hourbuilding',
name='friday',
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name='training',
name='friday',
field=models.BooleanField(default=True),
),
]

View File

@@ -0,0 +1,43 @@
# Generated by Django 5.2.8 on 2025-11-11 17:45
import django.db.models.deletion
import django.db.models.expressions
import django.db.models.functions.datetime
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0008_hourbuilding_friday_training_friday'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='student',
name='user',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='missionprofile',
name='mnum',
field=models.PositiveSmallIntegerField(default=0, null=True, verbose_name='Mission Number'),
),
migrations.AlterField(
model_name='missionprofile',
name='mtype',
field=models.CharField(choices=[('OTHER', 'OTHER'), ('PPL', 'PPL'), ('IR', 'IR'), ('CPL', 'CPL'), ('FI', 'FI'), ('PC', 'PC'), ('CHK', 'CHK_6M')], default='PPL', verbose_name='Mission Type'),
),
migrations.AlterField(
model_name='weekpreference',
name='student',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='flightslot.student', verbose_name='Student Selection'),
),
migrations.AlterField(
model_name='weekpreference',
name='week',
field=models.PositiveSmallIntegerField(auto_created=True, db_index=True, default=django.db.models.expressions.CombinedExpression(django.db.models.functions.datetime.ExtractWeek(django.db.models.functions.datetime.Now()), '+', models.Value(1)), verbose_name='Week Number'),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 5.2.8 on 2025-11-11 20:31
import datetime
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0009_student_user_alter_missionprofile_mnum_and_more'),
]
operations = [
migrations.AlterField(
model_name='hourbuildingleg',
name='time',
field=models.DurationField(default=models.DurationField(default=datetime.timedelta(0))),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 5.2.8 on 2025-11-11 20:33
import datetime
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0010_alter_hourbuildingleg_time'),
]
operations = [
migrations.AlterField(
model_name='hourbuildingleg',
name='time',
field=models.DurationField(default=datetime.timedelta(seconds=3600)),
),
]

View File

@@ -0,0 +1,34 @@
# Generated by Django 5.2.8 on 2025-11-12 09:47
import datetime
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0011_alter_hourbuildingleg_time'),
]
operations = [
migrations.AlterField(
model_name='course',
name='cnumber',
field=models.PositiveSmallIntegerField(default=2025),
),
migrations.AlterField(
model_name='course',
name='year',
field=models.PositiveSmallIntegerField(db_default=2025, editable=False),
),
migrations.AlterField(
model_name='missionprofile',
name='duration',
field=models.DurationField(default=datetime.timedelta(seconds=3600)),
),
migrations.AlterField(
model_name='weekpreference',
name='week',
field=models.PositiveSmallIntegerField(auto_created=True, db_default=46, db_index=True, verbose_name='Week Number'),
),
]

View File

@@ -0,0 +1,28 @@
# Generated by Django 5.2.8 on 2025-11-12 10:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0012_alter_course_cnumber_alter_course_year_and_more'),
]
operations = [
migrations.AddField(
model_name='course',
name='color',
field=models.CharField(choices=[('#ffffff', 'WHITE'), ('#ff0000', 'RED'), ('#00ff00', 'GREEN'), ('#0000ff', 'BLUE')], default='#ffffff'),
),
migrations.AlterField(
model_name='course',
name='ctype',
field=models.CharField(choices=[('FI', 'FI'), ('PPL', 'PPL'), ('ATPL', 'ATPL'), ('DL', 'DISTANCE'), ('OTHER', 'OTHER')]),
),
migrations.AlterField(
model_name='course',
name='year',
field=models.PositiveSmallIntegerField(default=2025),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.2.8 on 2025-11-12 10:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0013_course_color_alter_course_ctype_alter_course_year'),
]
operations = [
migrations.AddField(
model_name='student',
name='phone',
field=models.CharField(max_length=16, null=True),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 5.2.8 on 2025-11-12 10:31
import colorfield.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('flightslot', '0014_student_phone'),
]
operations = [
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')]),
),
]

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

View File

@@ -0,0 +1,9 @@
from django.utils.translation import gettext_lazy as _
from django.db import models
class AircraftTypes(models.TextChoices):
C152 = "C152", _("Cessna 152")
P208 = "P208", _("Tecnam P2008")
PA28 = "PA28", _("Piper PA28R")
C182 = "C182", _("Cessna 182Q")
P210 = "TWEN", _("Tecnam P2010")

View File

@@ -0,0 +1,52 @@
from django.utils.translation import gettext_lazy as _
from django.db import models
from datetime import date
from colorfield.fields import ColorField
class CourseTypes(models.TextChoices):
FI = "FI", _("FI")
PPL = "PPL", _("PPL")
ATPL = "ATPL", _("ATPL")
DISTANCE = "DL", _("DISTANCE")
OTHER = "OTHER",_("OTHER")
class Course(models.Model):
# Add colors according to table from Alessia
COLOR_PALETTE = [
("#ffffff","WHITE"),
("#ff0000", "RED"),
("#00ff00", "GREEN"),
("#0000ff", "BLUE")
]
id = models.AutoField(
primary_key=True
)
ctype = models.CharField(
null=False,
choices=CourseTypes,
verbose_name=_("Course Type")
)
cnumber = models.PositiveSmallIntegerField(
null=False,
default=date.today().year,
verbose_name=_("Course Number")
)
year = models.PositiveSmallIntegerField(
null=False,
default=date.today().year,
verbose_name=_("Year")
)
color = ColorField (
samples=COLOR_PALETTE,
verbose_name=_("Binder Color")
)
def __str__(self):
return f"{self.ctype}-{self.cnumber}"

View File

@@ -0,0 +1,103 @@
from django.utils.translation import gettext_lazy as _
from django.db import models
from datetime import timedelta
from ..models.weekpref import WeekPreference
from ..models.aircrafts import AircraftTypes
class HourBuilding(models.Model):
id = models.BigAutoField(
primary_key=True
)
weekpref = models.ForeignKey(
WeekPreference,
null=False,
on_delete=models.CASCADE
)
aircraft = models.CharField(
null=False,
choices=AircraftTypes
)
monday = models.BooleanField(
default=True,
null=False
)
tuesday = models.BooleanField(
default=True,
null=False
)
wednesday = models.BooleanField(
default=True,
null=False
)
thursday = models.BooleanField(
default=True,
null=False
)
friday = models.BooleanField(
default=True,
null=False
)
saturday = models.BooleanField(
default=True,
null=False
)
sunday = models.BooleanField(
default=True,
null=False
)
notes = models.TextField(
max_length=140,
null=True,
blank=True
)
class HourBuildingLeg(models.Model):
id = models.BigAutoField(
primary_key=True
)
hb = models.ForeignKey(
HourBuilding,
on_delete=models.CASCADE
)
departure = models.CharField(
null=False,
blank=False,
default="LILV",
max_length=4
)
destination = models.CharField(
null=False,
blank=False,
default="LILV",
max_length=4
)
time = models.DurationField(
null=False,
default = timedelta(hours=1)
)
stop = models.BooleanField(
default=False
)
def __str__(self):
if self.stop:
return "Refuelling Stop"
else:
return f"Flight Leg: {self.departure} -> {self.destination}"

View File

@@ -0,0 +1,108 @@
from django.utils.translation import gettext_lazy as _
from django.db import models
from datetime import timedelta
from ..models.weekpref import WeekPreference
class MissionType(models.TextChoices):
OTHER = "OTHER", _("OTHER")
PPL = "PPL", _("PPL")
IR = "IR", _("IR")
CPL = "CPL", _("CPL")
FI = "FI", _("FI")
PC = "PC", _("PC")
CHK = "CHK", _("CHK_6M")
class MissionProfile(models.Model):
id = models.AutoField(
primary_key=True
)
mtype = models.CharField(
null=False,
default=MissionType.PPL,
choices=MissionType,
verbose_name="Mission Type"
)
mnum = models.PositiveSmallIntegerField(
null=True,
default=0,
verbose_name="Mission Number"
)
duration = models.DurationField(
null=False,
default=timedelta(hours=1)
)
notes = models.TextField(
max_length=140,
null=True,
blank=True
)
def __str__(self):
return f"{self.mtype} {self.mnum}"
class Training(models.Model):
id = models.BigAutoField(
primary_key=True
)
weekpref = models.ForeignKey(
WeekPreference,
null=False,
on_delete=models.CASCADE
)
mission = models.ForeignKey(
MissionProfile,
null=True,
on_delete=models.CASCADE
)
monday = models.BooleanField(
default=True,
null=False
)
tuesday = models.BooleanField(
default=True,
null=False
)
wednesday = models.BooleanField(
default=True,
null=False
)
thursday = models.BooleanField(
default=True,
null=False
)
friday = models.BooleanField(
default=True,
null=False
)
saturday = models.BooleanField(
default=True,
null=False
)
sunday = models.BooleanField(
default=True,
null=False
)
notes = models.TextField(
max_length=140,
null=True,
blank=True
)
def __str__(self):
return f"{self.mission}"

View File

@@ -0,0 +1,50 @@
from django.db import models
from django.contrib.auth.models import User
from ..models.courses import Course
class Student(models.Model):
id = models.AutoField(
primary_key=True
)
email = models.EmailField(
null=False,
db_index=True
)
phone = models.CharField(
null=True,
max_length=16
)
name = models.CharField(
null=False,
max_length=32
)
surname = models.CharField(
null=False,
max_length=32
)
course = models.ForeignKey(
Course,
on_delete=models.DO_NOTHING,
null=True
)
active = models.BooleanField(
null=False,
default=True
)
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
null=True,
blank=True
)
def __str__(self):
return f"{self.surname} {self.name[0]}. => {self.course}"

View File

@@ -0,0 +1,28 @@
from django.db import models
from datetime import date
from ..models.students import Student
class WeekPreference(models.Model):
id = models.BigAutoField(
primary_key=True
)
week = models.PositiveSmallIntegerField(
null=False,
db_index=True,
db_default=date.today().isocalendar().week,
auto_created=True,
verbose_name="Week Number"
)
student = models.ForeignKey(
Student,
null=False,
db_index=True,
on_delete=models.DO_NOTHING,
verbose_name="Student Selection"
)
def __str__(self):
return f"Week {self.week} - {self.student.surname} {self.student.name[0]}."

View File

@@ -0,0 +1,30 @@
from django.db.models.signals import post_save
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, 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
# Create user
user = User.objects.create_user(
username=username,
email=student.email,
password=default_password(student=student)
)
student_group, _ = Group.objects.get_or_create(name="StudentGroup")
user.groups.add(student_group)
student.user = user
student.save()

View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

414
techdb/poetry.lock generated
View File

@@ -1,32 +1,49 @@
# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
[[package]]
name = "asgiref"
version = "3.8.1"
version = "3.10.0"
description = "ASGI specs, helper code, and adapters"
optional = false
python-versions = ">=3.8"
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"},
{file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"},
{file = "asgiref-3.10.0-py3-none-any.whl", hash = "sha256:aef8a81283a34d0ab31630c9b7dfe70c812c95eba78171367ca8745e88124734"},
{file = "asgiref-3.10.0.tar.gz", hash = "sha256:d89f2d8cd8b56dada7d52fa7dc8075baa08fb836560710d38c292a7a3f78c04e"},
]
[package.extras]
tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
tests = ["mypy (>=1.14.0)", "pytest", "pytest-asyncio"]
[[package]]
name = "diff-match-patch"
version = "20241021"
description = "Repackaging of Google's Diff Match and Patch libraries."
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "diff_match_patch-20241021-py3-none-any.whl", hash = "sha256:93cea333fb8b2bc0d181b0de5e16df50dd344ce64828226bda07728818936782"},
{file = "diff_match_patch-20241021.tar.gz", hash = "sha256:beae57a99fa48084532935ee2968b8661db861862ec82c6f21f4acdd6d835073"},
]
[package.extras]
dev = ["attribution (==1.8.0)", "black (==24.8.0)", "build (>=1)", "flit (==3.9.0)", "mypy (==1.12.1)", "ufmt (==2.7.3)", "usort (==1.0.8.post1)"]
[[package]]
name = "django"
version = "5.1.2"
version = "5.2.8"
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
optional = false
python-versions = ">=3.10"
groups = ["main"]
files = [
{file = "Django-5.1.2-py3-none-any.whl", hash = "sha256:f11aa87ad8d5617171e3f77e1d5d16f004b79a2cf5d2e1d2b97a6a1f8e9ba5ed"},
{file = "Django-5.1.2.tar.gz", hash = "sha256:bd7376f90c99f96b643722eee676498706c9fd7dc759f55ebfaf2c08ebcdf4f0"},
{file = "django-5.2.8-py3-none-any.whl", hash = "sha256:37e687f7bd73ddf043e2b6b97cfe02fcbb11f2dbb3adccc6a2b18c6daa054d7f"},
{file = "django-5.2.8.tar.gz", hash = "sha256:23254866a5bb9a2cfa6004e8b809ec6246eba4b58a7589bc2772f1bcc8456c7f"},
]
[package.dependencies]
asgiref = ">=3.8.1,<4"
asgiref = ">=3.8.1"
sqlparse = ">=0.3.1"
tzdata = {version = "*", markers = "sys_platform == \"win32\""}
@@ -34,109 +51,332 @@ tzdata = {version = "*", markers = "sys_platform == \"win32\""}
argon2 = ["argon2-cffi (>=19.1.0)"]
bcrypt = ["bcrypt"]
[[package]]
name = "django-colorfield"
version = "0.14.0"
description = "color field for django models with a nice color-picker in the admin."
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "django_colorfield-0.14.0-py3-none-any.whl", hash = "sha256:f169c4e7ad8f336e51d4ea81f866346e7d4f336f3766e54e144cd16ea7d84a0e"},
{file = "django_colorfield-0.14.0.tar.gz", hash = "sha256:478dbd3975a88f2ea2a9afc325faaca05c54ebf04ec985ce130f6dea39dfb899"},
]
[package.dependencies]
Pillow = ">=9.0.0"
[[package]]
name = "django-durationwidget"
version = "1.0.5"
description = "Django Duration field widget to handle duration field in the form"
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "django-durationwidget-1.0.5.tar.gz", hash = "sha256:a77bba14c173cbfe50071ae08759ca37218acb8567639687b0119647cb78c53f"},
{file = "django_durationwidget-1.0.5-py3-none-any.whl", hash = "sha256:7d14d5dfcf46c444fb203fe911cd058f78ba482c81ea2f0665db08369a1eff47"},
]
[package.dependencies]
Django = ">=1.11"
[[package]]
name = "django-import-export"
version = "4.3.13"
description = "Django application and library for importing and exporting data with included admin integration."
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "django_import_export-4.3.13-py3-none-any.whl", hash = "sha256:197e6a534948f3dcaeb395536e848a3fa267b9620bed5899314736d321fc6fc4"},
{file = "django_import_export-4.3.13.tar.gz", hash = "sha256:a0ebff68b470e578d1c05da83d7cb7545be1c42e1531720f49d2d9ec9a26f5bb"},
]
[package.dependencies]
diff-match-patch = "20241021"
Django = ">=4.2"
tablib = ">=3.7.0"
[package.extras]
all = ["tablib[all]"]
cli = ["tablib[cli]"]
docs = ["openpyxl (==3.1.5)", "psycopg[binary] (>=3.2.9)", "sphinx (==8.1.3)", "sphinx-rtd-theme (==3.0.1)"]
ods = ["tablib[ods]"]
pandas = ["tablib[pandas]"]
tests = ["chardet (==5.2.0)", "coverage (==7.6.4)", "django-extensions (==3.2.3)", "memory-profiler (==0.61.0)", "mysqlclient (==2.2.5)", "psycopg[binary] (>=3.2.9)", "pytz (==2024.2)", "setuptools-scm (==8.1.0)", "tablib[all] (>=3.7.0)"]
xls = ["tablib[xls]"]
xlsx = ["tablib[xlsx]"]
yaml = ["tablib[yaml]"]
[[package]]
name = "django-nested-admin"
version = "4.1.6"
description = "Django admin classes that allow for nested inlines"
optional = false
python-versions = ">=3.6"
groups = ["main"]
files = [
{file = "django_nested_admin-4.1.6-py3-none-any.whl", hash = "sha256:ae3e1d910631e6cc3b5815d80129f18c6c081b7dd7f775bf392d9bb1ac88ef93"},
{file = "django_nested_admin-4.1.6.tar.gz", hash = "sha256:0222475cc343e7b8813d7a5db583cddef15f5c0f44dbe17b91b4d682db7bd73a"},
]
[package.dependencies]
python-monkey-business = ">=1.0.0"
[package.extras]
dev = ["Pillow", "black", "dj-database-url", "django-selenosis", "flake8", "pytest", "pytest-cov", "pytest-django", "pytest-xdist", "selenium"]
test = ["Pillow", "dj-database-url", "django-selenosis", "pytest", "pytest-cov", "pytest-django", "pytest-xdist", "selenium"]
[[package]]
name = "pillow"
version = "12.0.0"
description = "Python Imaging Library (fork)"
optional = false
python-versions = ">=3.10"
groups = ["main"]
files = [
{file = "pillow-12.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:3adfb466bbc544b926d50fe8f4a4e6abd8c6bffd28a26177594e6e9b2b76572b"},
{file = "pillow-12.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1ac11e8ea4f611c3c0147424eae514028b5e9077dd99ab91e1bd7bc33ff145e1"},
{file = "pillow-12.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d49e2314c373f4c2b39446fb1a45ed333c850e09d0c59ac79b72eb3b95397363"},
{file = "pillow-12.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c7b2a63fd6d5246349f3d3f37b14430d73ee7e8173154461785e43036ffa96ca"},
{file = "pillow-12.0.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d64317d2587c70324b79861babb9c09f71fbb780bad212018874b2c013d8600e"},
{file = "pillow-12.0.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d77153e14b709fd8b8af6f66a3afbb9ed6e9fc5ccf0b6b7e1ced7b036a228782"},
{file = "pillow-12.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:32ed80ea8a90ee3e6fa08c21e2e091bba6eda8eccc83dbc34c95169507a91f10"},
{file = "pillow-12.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c828a1ae702fc712978bda0320ba1b9893d99be0badf2647f693cc01cf0f04fa"},
{file = "pillow-12.0.0-cp310-cp310-win32.whl", hash = "sha256:bd87e140e45399c818fac4247880b9ce719e4783d767e030a883a970be632275"},
{file = "pillow-12.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:455247ac8a4cfb7b9bc45b7e432d10421aea9fc2e74d285ba4072688a74c2e9d"},
{file = "pillow-12.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:6ace95230bfb7cd79ef66caa064bbe2f2a1e63d93471c3a2e1f1348d9f22d6b7"},
{file = "pillow-12.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0fd00cac9c03256c8b2ff58f162ebcd2587ad3e1f2e397eab718c47e24d231cc"},
{file = "pillow-12.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3475b96f5908b3b16c47533daaa87380c491357d197564e0ba34ae75c0f3257"},
{file = "pillow-12.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:110486b79f2d112cf6add83b28b627e369219388f64ef2f960fef9ebaf54c642"},
{file = "pillow-12.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5269cc1caeedb67e6f7269a42014f381f45e2e7cd42d834ede3c703a1d915fe3"},
{file = "pillow-12.0.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa5129de4e174daccbc59d0a3b6d20eaf24417d59851c07ebb37aeb02947987c"},
{file = "pillow-12.0.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bee2a6db3a7242ea309aa7ee8e2780726fed67ff4e5b40169f2c940e7eb09227"},
{file = "pillow-12.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:90387104ee8400a7b4598253b4c406f8958f59fcf983a6cea2b50d59f7d63d0b"},
{file = "pillow-12.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bc91a56697869546d1b8f0a3ff35224557ae7f881050e99f615e0119bf934b4e"},
{file = "pillow-12.0.0-cp311-cp311-win32.whl", hash = "sha256:27f95b12453d165099c84f8a8bfdfd46b9e4bda9e0e4b65f0635430027f55739"},
{file = "pillow-12.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:b583dc9070312190192631373c6c8ed277254aa6e6084b74bdd0a6d3b221608e"},
{file = "pillow-12.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:759de84a33be3b178a64c8ba28ad5c135900359e85fb662bc6e403ad4407791d"},
{file = "pillow-12.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:53561a4ddc36facb432fae7a9d8afbfaf94795414f5cdc5fc52f28c1dca90371"},
{file = "pillow-12.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:71db6b4c1653045dacc1585c1b0d184004f0d7e694c7b34ac165ca70c0838082"},
{file = "pillow-12.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2fa5f0b6716fc88f11380b88b31fe591a06c6315e955c096c35715788b339e3f"},
{file = "pillow-12.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:82240051c6ca513c616f7f9da06e871f61bfd7805f566275841af15015b8f98d"},
{file = "pillow-12.0.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55f818bd74fe2f11d4d7cbc65880a843c4075e0ac7226bc1a23261dbea531953"},
{file = "pillow-12.0.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b87843e225e74576437fd5b6a4c2205d422754f84a06942cfaf1dc32243e45a8"},
{file = "pillow-12.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c607c90ba67533e1b2355b821fef6764d1dd2cbe26b8c1005ae84f7aea25ff79"},
{file = "pillow-12.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:21f241bdd5080a15bc86d3466a9f6074a9c2c2b314100dd896ac81ee6db2f1ba"},
{file = "pillow-12.0.0-cp312-cp312-win32.whl", hash = "sha256:dd333073e0cacdc3089525c7df7d39b211bcdf31fc2824e49d01c6b6187b07d0"},
{file = "pillow-12.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:9fe611163f6303d1619bbcb653540a4d60f9e55e622d60a3108be0d5b441017a"},
{file = "pillow-12.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:7dfb439562f234f7d57b1ac6bc8fe7f838a4bd49c79230e0f6a1da93e82f1fad"},
{file = "pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0869154a2d0546545cde61d1789a6524319fc1897d9ee31218eae7a60ccc5643"},
{file = "pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a7921c5a6d31b3d756ec980f2f47c0cfdbce0fc48c22a39347a895f41f4a6ea4"},
{file = "pillow-12.0.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1ee80a59f6ce048ae13cda1abf7fbd2a34ab9ee7d401c46be3ca685d1999a399"},
{file = "pillow-12.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c50f36a62a22d350c96e49ad02d0da41dbd17ddc2e29750dbdba4323f85eb4a5"},
{file = "pillow-12.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5193fde9a5f23c331ea26d0cf171fbf67e3f247585f50c08b3e205c7aeb4589b"},
{file = "pillow-12.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bde737cff1a975b70652b62d626f7785e0480918dece11e8fef3c0cf057351c3"},
{file = "pillow-12.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a6597ff2b61d121172f5844b53f21467f7082f5fb385a9a29c01414463f93b07"},
{file = "pillow-12.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b817e7035ea7f6b942c13aa03bb554fc44fea70838ea21f8eb31c638326584e"},
{file = "pillow-12.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4f1231b7dec408e8670264ce63e9c71409d9583dd21d32c163e25213ee2a344"},
{file = "pillow-12.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e51b71417049ad6ab14c49608b4a24d8fb3fe605e5dfabfe523b58064dc3d27"},
{file = "pillow-12.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d120c38a42c234dc9a8c5de7ceaaf899cf33561956acb4941653f8bdc657aa79"},
{file = "pillow-12.0.0-cp313-cp313-win32.whl", hash = "sha256:4cc6b3b2efff105c6a1656cfe59da4fdde2cda9af1c5e0b58529b24525d0a098"},
{file = "pillow-12.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:4cf7fed4b4580601c4345ceb5d4cbf5a980d030fd5ad07c4d2ec589f95f09905"},
{file = "pillow-12.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:9f0b04c6b8584c2c193babcccc908b38ed29524b29dd464bc8801bf10d746a3a"},
{file = "pillow-12.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7fa22993bac7b77b78cae22bad1e2a987ddf0d9015c63358032f84a53f23cdc3"},
{file = "pillow-12.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f135c702ac42262573fe9714dfe99c944b4ba307af5eb507abef1667e2cbbced"},
{file = "pillow-12.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c85de1136429c524e55cfa4e033b4a7940ac5c8ee4d9401cc2d1bf48154bbc7b"},
{file = "pillow-12.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38df9b4bfd3db902c9c2bd369bcacaf9d935b2fff73709429d95cc41554f7b3d"},
{file = "pillow-12.0.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d87ef5795da03d742bf49439f9ca4d027cde49c82c5371ba52464aee266699a"},
{file = "pillow-12.0.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aff9e4d82d082ff9513bdd6acd4f5bd359f5b2c870907d2b0a9c5e10d40c88fe"},
{file = "pillow-12.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8d8ca2b210ada074d57fcee40c30446c9562e542fc46aedc19baf758a93532ee"},
{file = "pillow-12.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:99a7f72fb6249302aa62245680754862a44179b545ded638cf1fef59befb57ef"},
{file = "pillow-12.0.0-cp313-cp313t-win32.whl", hash = "sha256:4078242472387600b2ce8d93ade8899c12bf33fa89e55ec89fe126e9d6d5d9e9"},
{file = "pillow-12.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2c54c1a783d6d60595d3514f0efe9b37c8808746a66920315bfd34a938d7994b"},
{file = "pillow-12.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:26d9f7d2b604cd23aba3e9faf795787456ac25634d82cd060556998e39c6fa47"},
{file = "pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:beeae3f27f62308f1ddbcfb0690bf44b10732f2ef43758f169d5e9303165d3f9"},
{file = "pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d4827615da15cd59784ce39d3388275ec093ae3ee8d7f0c089b76fa87af756c2"},
{file = "pillow-12.0.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:3e42edad50b6909089750e65c91aa09aaf1e0a71310d383f11321b27c224ed8a"},
{file = "pillow-12.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e5d8efac84c9afcb40914ab49ba063d94f5dbdf5066db4482c66a992f47a3a3b"},
{file = "pillow-12.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:266cd5f2b63ff316d5a1bba46268e603c9caf5606d44f38c2873c380950576ad"},
{file = "pillow-12.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:58eea5ebe51504057dd95c5b77d21700b77615ab0243d8152793dc00eb4faf01"},
{file = "pillow-12.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f13711b1a5ba512d647a0e4ba79280d3a9a045aaf7e0cc6fbe96b91d4cdf6b0c"},
{file = "pillow-12.0.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6846bd2d116ff42cba6b646edf5bf61d37e5cbd256425fa089fee4ff5c07a99e"},
{file = "pillow-12.0.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c98fa880d695de164b4135a52fd2e9cd7b7c90a9d8ac5e9e443a24a95ef9248e"},
{file = "pillow-12.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa3ed2a29a9e9d2d488b4da81dcb54720ac3104a20bf0bd273f1e4648aff5af9"},
{file = "pillow-12.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d034140032870024e6b9892c692fe2968493790dd57208b2c37e3fb35f6df3ab"},
{file = "pillow-12.0.0-cp314-cp314-win32.whl", hash = "sha256:1b1b133e6e16105f524a8dec491e0586d072948ce15c9b914e41cdadd209052b"},
{file = "pillow-12.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:8dc232e39d409036af549c86f24aed8273a40ffa459981146829a324e0848b4b"},
{file = "pillow-12.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:d52610d51e265a51518692045e372a4c363056130d922a7351429ac9f27e70b0"},
{file = "pillow-12.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1979f4566bb96c1e50a62d9831e2ea2d1211761e5662afc545fa766f996632f6"},
{file = "pillow-12.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b2e4b27a6e15b04832fe9bf292b94b5ca156016bbc1ea9c2c20098a0320d6cf6"},
{file = "pillow-12.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fb3096c30df99fd01c7bf8e544f392103d0795b9f98ba71a8054bcbf56b255f1"},
{file = "pillow-12.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7438839e9e053ef79f7112c881cef684013855016f928b168b81ed5835f3e75e"},
{file = "pillow-12.0.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d5c411a8eaa2299322b647cd932586b1427367fd3184ffbb8f7a219ea2041ca"},
{file = "pillow-12.0.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7e091d464ac59d2c7ad8e7e08105eaf9dafbc3883fd7265ffccc2baad6ac925"},
{file = "pillow-12.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:792a2c0be4dcc18af9d4a2dfd8a11a17d5e25274a1062b0ec1c2d79c76f3e7f8"},
{file = "pillow-12.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:afbefa430092f71a9593a99ab6a4e7538bc9eabbf7bf94f91510d3503943edc4"},
{file = "pillow-12.0.0-cp314-cp314t-win32.whl", hash = "sha256:3830c769decf88f1289680a59d4f4c46c72573446352e2befec9a8512104fa52"},
{file = "pillow-12.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:905b0365b210c73afb0ebe9101a32572152dfd1c144c7e28968a331b9217b94a"},
{file = "pillow-12.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7"},
{file = "pillow-12.0.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b22bd8c974942477156be55a768f7aa37c46904c175be4e158b6a86e3a6b7ca8"},
{file = "pillow-12.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:805ebf596939e48dbb2e4922a1d3852cfc25c38160751ce02da93058b48d252a"},
{file = "pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cae81479f77420d217def5f54b5b9d279804d17e982e0f2fa19b1d1e14ab5197"},
{file = "pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aeaefa96c768fc66818730b952a862235d68825c178f1b3ffd4efd7ad2edcb7c"},
{file = "pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09f2d0abef9e4e2f349305a4f8cc784a8a6c2f58a8c4892eea13b10a943bd26e"},
{file = "pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bdee52571a343d721fb2eb3b090a82d959ff37fc631e3f70422e0c2e029f3e76"},
{file = "pillow-12.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b290fd8aa38422444d4b50d579de197557f182ef1068b75f5aa8558638b8d0a5"},
{file = "pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353"},
]
[package.extras]
docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
fpx = ["olefile"]
mic = ["olefile"]
test-arrow = ["arro3-compute", "arro3-core", "nanoarrow", "pyarrow"]
tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma (>=5)", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"]
xmp = ["defusedxml"]
[[package]]
name = "psycopg2-binary"
version = "2.9.10"
version = "2.9.11"
description = "psycopg2 - Python-PostgreSQL Database Adapter"
optional = false
python-versions = ">=3.8"
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "psycopg2-binary-2.9.10.tar.gz", hash = "sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2"},
{file = "psycopg2_binary-2.9.10-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:0ea8e3d0ae83564f2fc554955d327fa081d065c8ca5cc6d2abb643e2c9c1200f"},
{file = "psycopg2_binary-2.9.10-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:3e9c76f0ac6f92ecfc79516a8034a544926430f7b080ec5a0537bca389ee0906"},
{file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ad26b467a405c798aaa1458ba09d7e2b6e5f96b1ce0ac15d82fd9f95dc38a92"},
{file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:270934a475a0e4b6925b5f804e3809dd5f90f8613621d062848dd82f9cd62007"},
{file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:48b338f08d93e7be4ab2b5f1dbe69dc5e9ef07170fe1f86514422076d9c010d0"},
{file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4152f8f76d2023aac16285576a9ecd2b11a9895373a1f10fd9db54b3ff06b4"},
{file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:32581b3020c72d7a421009ee1c6bf4a131ef5f0a968fab2e2de0c9d2bb4577f1"},
{file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:2ce3e21dc3437b1d960521eca599d57408a695a0d3c26797ea0f72e834c7ffe5"},
{file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e984839e75e0b60cfe75e351db53d6db750b00de45644c5d1f7ee5d1f34a1ce5"},
{file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c4745a90b78e51d9ba06e2088a2fe0c693ae19cc8cb051ccda44e8df8a6eb53"},
{file = "psycopg2_binary-2.9.10-cp310-cp310-win32.whl", hash = "sha256:e5720a5d25e3b99cd0dc5c8a440570469ff82659bb09431c1439b92caf184d3b"},
{file = "psycopg2_binary-2.9.10-cp310-cp310-win_amd64.whl", hash = "sha256:3c18f74eb4386bf35e92ab2354a12c17e5eb4d9798e4c0ad3a00783eae7cd9f1"},
{file = "psycopg2_binary-2.9.10-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:04392983d0bb89a8717772a193cfaac58871321e3ec69514e1c4e0d4957b5aff"},
{file = "psycopg2_binary-2.9.10-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:1a6784f0ce3fec4edc64e985865c17778514325074adf5ad8f80636cd029ef7c"},
{file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5f86c56eeb91dc3135b3fd8a95dc7ae14c538a2f3ad77a19645cf55bab1799c"},
{file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b3d2491d4d78b6b14f76881905c7a8a8abcf974aad4a8a0b065273a0ed7a2cb"},
{file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2286791ececda3a723d1910441c793be44625d86d1a4e79942751197f4d30341"},
{file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:512d29bb12608891e349af6a0cccedce51677725a921c07dba6342beaf576f9a"},
{file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5a507320c58903967ef7384355a4da7ff3f28132d679aeb23572753cbf2ec10b"},
{file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6d4fa1079cab9018f4d0bd2db307beaa612b0d13ba73b5c6304b9fe2fb441ff7"},
{file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:851485a42dbb0bdc1edcdabdb8557c09c9655dfa2ca0460ff210522e073e319e"},
{file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:35958ec9e46432d9076286dda67942ed6d968b9c3a6a2fd62b48939d1d78bf68"},
{file = "psycopg2_binary-2.9.10-cp311-cp311-win32.whl", hash = "sha256:ecced182e935529727401b24d76634a357c71c9275b356efafd8a2a91ec07392"},
{file = "psycopg2_binary-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:ee0e8c683a7ff25d23b55b11161c2663d4b099770f6085ff0a20d4505778d6b4"},
{file = "psycopg2_binary-2.9.10-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:880845dfe1f85d9d5f7c412efea7a08946a46894537e4e5d091732eb1d34d9a0"},
{file = "psycopg2_binary-2.9.10-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9440fa522a79356aaa482aa4ba500b65f28e5d0e63b801abf6aa152a29bd842a"},
{file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3923c1d9870c49a2d44f795df0c889a22380d36ef92440ff618ec315757e539"},
{file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b2c956c028ea5de47ff3a8d6b3cc3330ab45cf0b7c3da35a2d6ff8420896526"},
{file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f758ed67cab30b9a8d2833609513ce4d3bd027641673d4ebc9c067e4d208eec1"},
{file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cd9b4f2cfab88ed4a9106192de509464b75a906462fb846b936eabe45c2063e"},
{file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dc08420625b5a20b53551c50deae6e231e6371194fa0651dbe0fb206452ae1f"},
{file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d7cd730dfa7c36dbe8724426bf5612798734bff2d3c3857f36f2733f5bfc7c00"},
{file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:155e69561d54d02b3c3209545fb08938e27889ff5a10c19de8d23eb5a41be8a5"},
{file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3cc28a6fd5a4a26224007712e79b81dbaee2ffb90ff406256158ec4d7b52b47"},
{file = "psycopg2_binary-2.9.10-cp312-cp312-win32.whl", hash = "sha256:ec8a77f521a17506a24a5f626cb2aee7850f9b69a0afe704586f63a464f3cd64"},
{file = "psycopg2_binary-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:18c5ee682b9c6dd3696dad6e54cc7ff3a1a9020df6a5c0f861ef8bfd338c3ca0"},
{file = "psycopg2_binary-2.9.10-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:26540d4a9a4e2b096f1ff9cce51253d0504dca5a85872c7f7be23be5a53eb18d"},
{file = "psycopg2_binary-2.9.10-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e217ce4d37667df0bc1c397fdcd8de5e81018ef305aed9415c3b093faaeb10fb"},
{file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:245159e7ab20a71d989da00f280ca57da7641fa2cdcf71749c193cea540a74f7"},
{file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c4ded1a24b20021ebe677b7b08ad10bf09aac197d6943bfe6fec70ac4e4690d"},
{file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3abb691ff9e57d4a93355f60d4f4c1dd2d68326c968e7db17ea96df3c023ef73"},
{file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8608c078134f0b3cbd9f89b34bd60a943b23fd33cc5f065e8d5f840061bd0673"},
{file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:230eeae2d71594103cd5b93fd29d1ace6420d0b86f4778739cb1a5a32f607d1f"},
{file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"},
{file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"},
{file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"},
{file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"},
{file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"},
{file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"},
{file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:056470c3dc57904bbf63d6f534988bafc4e970ffd50f6271fc4ee7daad9498a5"},
{file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aa0e31fa4bb82578f3a6c74a73c273367727de397a7a0f07bd83cbea696baa"},
{file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8de718c0e1c4b982a54b41779667242bc630b2197948405b7bd8ce16bcecac92"},
{file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5c370b1e4975df846b0277b4deba86419ca77dbc25047f535b0bb03d1a544d44"},
{file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:ffe8ed017e4ed70f68b7b371d84b7d4a790368db9203dfc2d222febd3a9c8863"},
{file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:8aecc5e80c63f7459a1a2ab2c64df952051df196294d9f739933a9f6687e86b3"},
{file = "psycopg2_binary-2.9.10-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:7a813c8bdbaaaab1f078014b9b0b13f5de757e2b5d9be6403639b298a04d218b"},
{file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d00924255d7fc916ef66e4bf22f354a940c67179ad3fd7067d7a0a9c84d2fbfc"},
{file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7559bce4b505762d737172556a4e6ea8a9998ecac1e39b5233465093e8cee697"},
{file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8b58f0a96e7a1e341fc894f62c1177a7c83febebb5ff9123b579418fdc8a481"},
{file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b269105e59ac96aba877c1707c600ae55711d9dcd3fc4b5012e4af68e30c648"},
{file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:79625966e176dc97ddabc142351e0409e28acf4660b88d1cf6adb876d20c490d"},
{file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:8aabf1c1a04584c168984ac678a668094d831f152859d06e055288fa515e4d30"},
{file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:19721ac03892001ee8fdd11507e6a2e01f4e37014def96379411ca99d78aeb2c"},
{file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7f5d859928e635fa3ce3477704acee0f667b3a3d3e4bb109f2b18d4005f38287"},
{file = "psycopg2_binary-2.9.10-cp39-cp39-win32.whl", hash = "sha256:3216ccf953b3f267691c90c6fe742e45d890d8272326b4a8b20850a03d05b7b8"},
{file = "psycopg2_binary-2.9.10-cp39-cp39-win_amd64.whl", hash = "sha256:30e34c4e97964805f715206c7b789d54a78b70f3ff19fbe590104b71c45600e5"},
{file = "psycopg2-binary-2.9.11.tar.gz", hash = "sha256:b6aed9e096bf63f9e75edf2581aa9a7e7186d97ab5c177aa6c87797cd591236c"},
{file = "psycopg2_binary-2.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d6fe6b47d0b42ce1c9f1fa3e35bb365011ca22e39db37074458f27921dca40f2"},
{file = "psycopg2_binary-2.9.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a6c0e4262e089516603a09474ee13eabf09cb65c332277e39af68f6233911087"},
{file = "psycopg2_binary-2.9.11-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c47676e5b485393f069b4d7a811267d3168ce46f988fa602658b8bb901e9e64d"},
{file = "psycopg2_binary-2.9.11-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:a28d8c01a7b27a1e3265b11250ba7557e5f72b5ee9e5f3a2fa8d2949c29bf5d2"},
{file = "psycopg2_binary-2.9.11-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f3f2732cf504a1aa9e9609d02f79bea1067d99edf844ab92c247bbca143303b"},
{file = "psycopg2_binary-2.9.11-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:865f9945ed1b3950d968ec4690ce68c55019d79e4497366d36e090327ce7db14"},
{file = "psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:91537a8df2bde69b1c1db01d6d944c831ca793952e4f57892600e96cee95f2cd"},
{file = "psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4dca1f356a67ecb68c81a7bc7809f1569ad9e152ce7fd02c2f2036862ca9f66b"},
{file = "psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0da4de5c1ac69d94ed4364b6cbe7190c1a70d325f112ba783d83f8440285f152"},
{file = "psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37d8412565a7267f7d79e29ab66876e55cb5e8e7b3bbf94f8206f6795f8f7e7e"},
{file = "psycopg2_binary-2.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:c665f01ec8ab273a61c62beeb8cce3014c214429ced8a308ca1fc410ecac3a39"},
{file = "psycopg2_binary-2.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0e8480afd62362d0a6a27dd09e4ca2def6fa50ed3a4e7c09165266106b2ffa10"},
{file = "psycopg2_binary-2.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:763c93ef1df3da6d1a90f86ea7f3f806dc06b21c198fa87c3c25504abec9404a"},
{file = "psycopg2_binary-2.9.11-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e164359396576a3cc701ba8af4751ae68a07235d7a380c631184a611220d9a4"},
{file = "psycopg2_binary-2.9.11-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:d57c9c387660b8893093459738b6abddbb30a7eab058b77b0d0d1c7d521ddfd7"},
{file = "psycopg2_binary-2.9.11-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2c226ef95eb2250974bf6fa7a842082b31f68385c4f3268370e3f3870e7859ee"},
{file = "psycopg2_binary-2.9.11-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a311f1edc9967723d3511ea7d2708e2c3592e3405677bf53d5c7246753591fbb"},
{file = "psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ebb415404821b6d1c47353ebe9c8645967a5235e6d88f914147e7fd411419e6f"},
{file = "psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f07c9c4a5093258a03b28fab9b4f151aa376989e7f35f855088234e656ee6a94"},
{file = "psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:00ce1830d971f43b667abe4a56e42c1e2d594b32da4802e44a73bacacb25535f"},
{file = "psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cffe9d7697ae7456649617e8bb8d7a45afb71cd13f7ab22af3e5c61f04840908"},
{file = "psycopg2_binary-2.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:304fd7b7f97eef30e91b8f7e720b3db75fee010b520e434ea35ed1ff22501d03"},
{file = "psycopg2_binary-2.9.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:be9b840ac0525a283a96b556616f5b4820e0526addb8dcf6525a0fa162730be4"},
{file = "psycopg2_binary-2.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f090b7ddd13ca842ebfe301cd587a76a4cf0913b1e429eb92c1be5dbeb1a19bc"},
{file = "psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ab8905b5dcb05bf3fb22e0cf90e10f469563486ffb6a96569e51f897c750a76a"},
{file = "psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:bf940cd7e7fec19181fdbc29d76911741153d51cab52e5c21165f3262125685e"},
{file = "psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fa0f693d3c68ae925966f0b14b8edda71696608039f4ed61b1fe9ffa468d16db"},
{file = "psycopg2_binary-2.9.11-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a1cf393f1cdaf6a9b57c0a719a1068ba1069f022a59b8b1fe44b006745b59757"},
{file = "psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef7a6beb4beaa62f88592ccc65df20328029d721db309cb3250b0aae0fa146c3"},
{file = "psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:31b32c457a6025e74d233957cc9736742ac5a6cb196c6b68499f6bb51390bd6a"},
{file = "psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:edcb3aeb11cb4bf13a2af3c53a15b3d612edeb6409047ea0b5d6a21a9d744b34"},
{file = "psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b6d93d7c0b61a1dd6197d208ab613eb7dcfdcca0a49c42ceb082257991de9d"},
{file = "psycopg2_binary-2.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:b33fabeb1fde21180479b2d4667e994de7bbf0eec22832ba5d9b5e4cf65b6c6d"},
{file = "psycopg2_binary-2.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b8fb3db325435d34235b044b199e56cdf9ff41223a4b9752e8576465170bb38c"},
{file = "psycopg2_binary-2.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:366df99e710a2acd90efed3764bb1e28df6c675d33a7fb40df9b7281694432ee"},
{file = "psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8c55b385daa2f92cb64b12ec4536c66954ac53654c7f15a203578da4e78105c0"},
{file = "psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c0377174bf1dd416993d16edc15357f6eb17ac998244cca19bc67cdc0e2e5766"},
{file = "psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5c6ff3335ce08c75afaed19e08699e8aacf95d4a260b495a4a8545244fe2ceb3"},
{file = "psycopg2_binary-2.9.11-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:84011ba3109e06ac412f95399b704d3d6950e386b7994475b231cf61eec2fc1f"},
{file = "psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ba34475ceb08cccbdd98f6b46916917ae6eeb92b5ae111df10b544c3a4621dc4"},
{file = "psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b31e90fdd0f968c2de3b26ab014314fe814225b6c324f770952f7d38abf17e3c"},
{file = "psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:d526864e0f67f74937a8fce859bd56c979f5e2ec57ca7c627f5f1071ef7fee60"},
{file = "psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04195548662fa544626c8ea0f06561eb6203f1984ba5b4562764fbeb4c3d14b1"},
{file = "psycopg2_binary-2.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:efff12b432179443f54e230fdf60de1f6cc726b6c832db8701227d089310e8aa"},
{file = "psycopg2_binary-2.9.11-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:92e3b669236327083a2e33ccfa0d320dd01b9803b3e14dd986a4fc54aa00f4e1"},
{file = "psycopg2_binary-2.9.11-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e0deeb03da539fa3577fcb0b3f2554a97f7e5477c246098dbb18091a4a01c16f"},
{file = "psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b52a3f9bb540a3e4ec0f6ba6d31339727b2950c9772850d6545b7eae0b9d7c5"},
{file = "psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:db4fd476874ccfdbb630a54426964959e58da4c61c9feba73e6094d51303d7d8"},
{file = "psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:47f212c1d3be608a12937cc131bd85502954398aaa1320cb4c14421a0ffccf4c"},
{file = "psycopg2_binary-2.9.11-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e35b7abae2b0adab776add56111df1735ccc71406e56203515e228a8dc07089f"},
{file = "psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fcf21be3ce5f5659daefd2b3b3b6e4727b028221ddc94e6c1523425579664747"},
{file = "psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9bd81e64e8de111237737b29d68039b9c813bdf520156af36d26819c9a979e5f"},
{file = "psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:32770a4d666fbdafab017086655bcddab791d7cb260a16679cc5a7338b64343b"},
{file = "psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3cb3a676873d7506825221045bd70e0427c905b9c8ee8d6acd70cfcbd6e576d"},
{file = "psycopg2_binary-2.9.11-cp314-cp314-win_amd64.whl", hash = "sha256:4012c9c954dfaccd28f94e84ab9f94e12df76b4afb22331b1f0d3154893a6316"},
{file = "psycopg2_binary-2.9.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:20e7fb94e20b03dcc783f76c0865f9da39559dcc0c28dd1a3fce0d01902a6b9c"},
{file = "psycopg2_binary-2.9.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4bdab48575b6f870f465b397c38f1b415520e9879fdf10a53ee4f49dcbdf8a21"},
{file = "psycopg2_binary-2.9.11-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9d3a9edcfbe77a3ed4bc72836d466dfce4174beb79eda79ea155cc77237ed9e8"},
{file = "psycopg2_binary-2.9.11-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:44fc5c2b8fa871ce7f0023f619f1349a0aa03a0857f2c96fbc01c657dcbbdb49"},
{file = "psycopg2_binary-2.9.11-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9c55460033867b4622cda1b6872edf445809535144152e5d14941ef591980edf"},
{file = "psycopg2_binary-2.9.11-cp39-cp39-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2d11098a83cca92deaeaed3d58cfd150d49b3b06ee0d0852be466bf87596899e"},
{file = "psycopg2_binary-2.9.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:691c807d94aecfbc76a14e1408847d59ff5b5906a04a23e12a89007672b9e819"},
{file = "psycopg2_binary-2.9.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:8b81627b691f29c4c30a8f322546ad039c40c328373b11dff7490a3e1b517855"},
{file = "psycopg2_binary-2.9.11-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:b637d6d941209e8d96a072d7977238eea128046effbf37d1d8b2c0764750017d"},
{file = "psycopg2_binary-2.9.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:41360b01c140c2a03d346cec3280cf8a71aa07d94f3b1509fa0161c366af66b4"},
{file = "psycopg2_binary-2.9.11-cp39-cp39-win_amd64.whl", hash = "sha256:875039274f8a2361e5207857899706da840768e2a775bf8c65e82f60b197df02"},
]
[[package]]
name = "python-monkey-business"
version = "1.1.0"
description = "Utility functions for monkey-patching python code"
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "python-monkey-business-1.1.0.tar.gz", hash = "sha256:8393839cc741415ed5ddc2bd58e2d4ce07f966a7d26b7aebff19dcec64818edc"},
{file = "python_monkey_business-1.1.0-py2.py3-none-any.whl", hash = "sha256:15b4f603c749ba9a7b4f1acd36af023a6c5ba0f7e591c945f8253f0ef44bf389"},
]
[[package]]
name = "sqlparse"
version = "0.5.1"
version = "0.5.3"
description = "A non-validating SQL parser."
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "sqlparse-0.5.1-py3-none-any.whl", hash = "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4"},
{file = "sqlparse-0.5.1.tar.gz", hash = "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e"},
{file = "sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca"},
{file = "sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272"},
]
[package.extras]
dev = ["build", "hatch"]
doc = ["sphinx"]
[[package]]
name = "tablib"
version = "3.9.0"
description = "Format agnostic tabular data library (XLS, JSON, YAML, CSV, etc.)"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "tablib-3.9.0-py3-none-any.whl", hash = "sha256:eda17cd0d4dda614efc0e710227654c60ddbeb1ca92cdcfc5c3bd1fc5f5a6e4a"},
{file = "tablib-3.9.0.tar.gz", hash = "sha256:1b6abd8edb0f35601e04c6161d79660fdcde4abb4a54f66cc9f9054bd55d5fe2"},
]
[package.extras]
all = ["odfpy", "openpyxl (>=2.6.0)", "pandas", "pyyaml", "tabulate", "xlrd", "xlwt"]
cli = ["tabulate"]
ods = ["odfpy"]
pandas = ["pandas"]
xls = ["xlrd", "xlwt"]
xlsx = ["openpyxl (>=2.6.0)"]
yaml = ["pyyaml"]
[[package]]
name = "tzdata"
version = "2024.2"
version = "2025.2"
description = "Provider of IANA time zone data"
optional = false
python-versions = ">=2"
groups = ["main"]
markers = "sys_platform == \"win32\""
files = [
{file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"},
{file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"},
{file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"},
{file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"},
]
[metadata]
lock-version = "2.0"
lock-version = "2.1"
python-versions = "^3.12"
content-hash = "c3b2acd3f06588e63224efb9ff8fc91a396c95e22862e40427c05b788901ea24"
content-hash = "8d8926bda0e1b7cdb8a1e57168dd3acc0f3240e34d4e2faf613b844d989dad30"

View File

@@ -1,7 +1,7 @@
[tool.poetry]
name = "techdb"
version = "0.1.0"
description = "CantorAit Tech Organized Parts Storage"
description = "CantorAir Tech Organized Parts Storage"
authors = ["Emanuele <ema.trabattoni@gmail.com>"]
readme = "README.md"
@@ -9,6 +9,10 @@ readme = "README.md"
python = "^3.12"
django = "^5.1.2"
psycopg2-binary = "^2.9.10"
django-nested-admin = "^4.1.1"
django-durationwidget = "^1.0.5"
django-import-export = "^4.3.13"
django-colorfield = "^0.14.0"
[build-system]

BIN
techdb/static/cantorair.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/5.1/ref/settings/
"""
from pathlib import Path
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
@@ -37,7 +38,10 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'catops',
'nested_admin',
'flightslot',
'durationwidget',
'colorfield'
]
MIDDLEWARE = [
@@ -55,7 +59,7 @@ ROOT_URLCONF = 'techdb.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'DIRS': [os.path.join(BASE_DIR, 'templates/')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
@@ -70,6 +74,9 @@ TEMPLATES = [
WSGI_APPLICATION = 'techdb.wsgi.application'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases

View File

@@ -20,3 +20,7 @@ from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
admin.site.site_header = "CantorAir Flight Scheduler"
admin.site.site_title = "CantorAir Flight Scheduler"
admin.site.index_title = "Welcome to CantorAir Flight Scheduler Portal"

View File

@@ -0,0 +1,22 @@
{% extends "admin/base.html" %}
{% load static %}
{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
{% block branding %}
<h1 id="site-name">
<a href="{% url 'admin:index' %}">
<img src="{% static 'cantorair.jpg' %}" height="60px" />
</a>
</h1>
<div id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></div>
{% if user.is_anonymous %}
{% include "admin/color_theme_toggle.html" %}
{% endif %}
{% endblock %}
{% block nav-global %}{% endblock %}