added database

This commit is contained in:
Faraphel 2023-11-28 22:54:24 +01:00
parent 78e7752b3e
commit fc05ea9319
14 changed files with 316 additions and 8 deletions

7
.gitignore vendored
View file

@ -1,2 +1,5 @@
.idea/ .idea
Palto/db.sqlite3 venv
media
static-collected
db.sqlite3

View file

@ -16,8 +16,5 @@ RUN pip install -r requirements.txt
# Expose the port on which your Django application will run # Expose the port on which your Django application will run
EXPOSE 80 EXPOSE 80
# Set the working directory in the Django application
WORKDIR ./Palto
# Start the Django application # Start the Django application
ENTRYPOINT ["python", "manage.py", "runserver_plus", "0.0.0.0:80"] ENTRYPOINT ["python", "manage.py", "runserver_plus", "0.0.0.0:80"]

63
Palto/Palto/admin.py Normal file
View file

@ -0,0 +1,63 @@
from django.contrib import admin
from .models import (Department, StudentGroup, TeachingUnit, StudentCard, TeachingSession, Attendance, Absence,
AbsenceAttachment, User)
# Register your models here.
@admin.register(User)
class AdminUser(admin.ModelAdmin):
list_display = ("id", "username", "email", "first_name", "last_name", "is_staff")
search_fields = ("id", "username", "email", "first_name", "last_name", "is_staff")
list_filter = ("is_staff",)
@admin.register(Department)
class AdminDepartment(admin.ModelAdmin):
list_display = ("id", "name")
search_fields = ("id", "name")
@admin.register(StudentGroup)
class AdminStudentGroup(admin.ModelAdmin):
list_display = ("id", "name")
search_fields = ("id", "name")
@admin.register(TeachingUnit)
class AdminTeachingUnit(admin.ModelAdmin):
list_display = ("id", "name")
search_fields = ("id", "name")
@admin.register(StudentCard)
class AdminStudentCard(admin.ModelAdmin):
list_display = ("id", "uid", "owner")
search_fields = ("id", "uid", "owner")
readonly_fields = ("uid",)
@admin.register(TeachingSession)
class AdminTeachingSession(admin.ModelAdmin):
list_display = ("id", "start", "end", "duration", "teacher")
search_fields = ("id", "start", "end", "duration", "teacher")
list_filter = ("start", "duration")
@admin.register(Attendance)
class AdminAttendance(admin.ModelAdmin):
list_display = ("id", "date", "student")
search_fields = ("id", "date", "student")
list_filter = ("date",)
@admin.register(Absence)
class AdminAbsence(admin.ModelAdmin):
list_display = ("id", "message", "student")
search_fields = ("id", "message", "student")
@admin.register(AbsenceAttachment)
class AdminAbsenceAttachment(admin.ModelAdmin):
list_display = ("id", "content", "absence")
search_fields = ("id", "content", "absence")

7
Palto/Palto/apps.py Normal file
View file

@ -0,0 +1,7 @@
from django.apps import AppConfig
class PaltoConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = "Palto.Palto"
label = "Palto"

View file

210
Palto/Palto/models.py Normal file
View file

@ -0,0 +1,210 @@
import uuid
from datetime import datetime, timedelta
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AbstractUser
from django.db import models
# Create your models here.
class User(AbstractUser):
"""
A user.
Same as the base Django user, but the id is now an uuid instead of an int.
"""
id: uuid.UUID = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False, max_length=36)
def __repr__(self):
return f"<{self.__class__.__name__} id={str(self.id)[:8]} username={self.username!r}>"
class Department(models.Model):
"""
A scholar department.
For example, a same server can handle both a science department and a sport department.
ALl have their own managers, teachers and student.
"""
id: uuid.UUID = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False, max_length=36)
name: str = models.CharField(max_length=64)
mail: str = models.EmailField()
managers = models.ManyToManyField(to=get_user_model(), blank=True, related_name="managing_departments")
teachers = models.ManyToManyField(to=get_user_model(), blank=True, related_name="teaching_departments")
students = models.ManyToManyField(to=get_user_model(), blank=True, related_name="studying_departments")
def __repr__(self):
return f"<{self.__class__.__name__} id={str(self.id)[:8]} name={self.name!r}>"
def __str__(self):
return self.name
class StudentGroup(models.Model):
"""
A student group.
This make selecting multiple students with a specificity easier.
For example, if students are registered to an English course,
putting them in a same group make them easier to select.
"""
id: uuid.UUID = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False, max_length=36)
name: str = models.CharField(max_length=128)
students = models.ManyToManyField(to=get_user_model(), blank=True, related_name="student_groups")
def __repr__(self):
return f"<{self.__class__.__name__} id={str(self.id)[:8]} name={self.name!r}>"
def __str__(self):
return self.name
class TeachingUnit(models.Model):
"""
A teaching unit.
This represents a unit that can be taught to groups of student.
For example, Maths, English, French, Computer Science are all teaching units.
The registered groups are groups of student allowed to participate in these units.
"""
id: uuid.UUID = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False, max_length=36)
name: str = models.CharField(max_length=64)
department = models.ForeignKey(to=Department, on_delete=models.CASCADE, related_name="teaching_units")
managers = models.ManyToManyField(to=get_user_model(), blank=True, related_name="managing_units")
teachers = models.ManyToManyField(to=get_user_model(), blank=True, related_name="teaching_units")
student_groups = models.ManyToManyField(to=StudentGroup, blank=True, related_name="studying_units")
def __repr__(self):
return f"<{self.__class__.__name__} id={str(self.id)[:8]} name={self.name!r}>"
def __str__(self):
return self.name
class StudentCard(models.Model):
"""
A student card.
This represents a student NFC card.
"""
id: uuid.UUID = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False, max_length=36)
uid: bytes = models.BinaryField(max_length=7)
owner: User = models.ForeignKey(to=get_user_model(), on_delete=models.CASCADE, related_name="student_cards")
def __repr__(self):
return f"<{self.__class__.__name__} id={str(self.id)[:8]} owner={self.owner.username!r}>"
class TeachingSession(models.Model):
"""
A session of a teaching unit.
For example, a session of English would be a single course of this unit.
It references a teacher responsible for scanning the student cards, student attendances and student absences.
"""
id: uuid.UUID = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False, max_length=36)
start: datetime = models.DateTimeField()
duration: timedelta = models.DurationField()
note: str = models.TextField(blank=True)
unit = models.ForeignKey(to=TeachingUnit, on_delete=models.CASCADE, related_name="sessions")
group = models.ForeignKey(to=StudentGroup, on_delete=models.CASCADE, related_name="teaching_sessions")
teacher = models.ForeignKey(to=get_user_model(), on_delete=models.CASCADE, related_name="teaching_sessions")
def __repr__(self):
return f"<{self.__class__.__name__} id={str(self.id)[:8]} unit={self.unit.name!r} start={self.start}>"
def __str__(self):
return f"{self.unit.name} ({self.start})"
@property
def end(self) -> datetime:
return self.start + self.duration
class Attendance(models.Model):
"""
A student attendance to a session.
When a student confirm his presence to a session, this is represented by this model.
"""
id: uuid.UUID = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False, max_length=36)
date: datetime = models.DateTimeField()
student: User = models.ForeignKey(
to=get_user_model(),
on_delete=models.CASCADE,
related_name="attended_sessions"
)
session: TeachingSession = models.ForeignKey(
to=TeachingSession,
on_delete=models.CASCADE,
related_name="attendances"
)
def __repr__(self):
return (
f"<{self.__class__.__name__} "
f"id={str(self.id)[:8]} "
f"student={self.student.username} "
f"session={str(self.session.id)[:8]}"
f">"
)
class Absence(models.Model):
"""
A student justified absence to a session.
When a student signal his absence to a session, this is represented by this model.
"""
id: uuid.UUID = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False, max_length=36)
message: str = models.TextField()
student: User = models.ForeignKey(to=get_user_model(), on_delete=models.CASCADE, related_name="absented_sessions")
session: TeachingSession = models.ManyToManyField(to=TeachingSession, blank=True, related_name="absences")
def __repr__(self):
return (
f"<{self.__class__.__name__} "
f"id={str(self.id)[:8]} "
f"student={self.student.username} "
f"session={str(self.session.id)[:8]}"
f">"
)
def __str__(self):
return f"[{str(self.id)[:8]}] {self.student}"
class AbsenceAttachment(models.Model):
"""
An attachment to a student justified absence.
The student can add additional files to justify his absence.
"""
id: uuid.UUID = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False, max_length=36)
content = models.FileField(upload_to="absence/attachment/")
absence = models.ForeignKey(to=Absence, on_delete=models.CASCADE, related_name="attachments")
def __repr__(self):
return f"<{self.__class__.__name__} id={str(self.id)[:8]} content={self.content!r}>"

3
Palto/Palto/tests.py Normal file
View file

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

3
Palto/Palto/views.py Normal file
View file

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

0
Palto/__init__.py Normal file
View file

View file

@ -50,6 +50,8 @@ INSTALLED_APPS = [
'rest_framework', 'rest_framework',
"debug_toolbar", "debug_toolbar",
'django_extensions', 'django_extensions',
"Palto.Palto",
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@ -129,7 +131,13 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/ # https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = 'static/' STATIC_URL = "static/"
STATIC_ROOT = BASE_DIR / "static-collected/"
# Media files
MEDIA_URL = "media/"
MEDIA_ROOT = BASE_DIR / "media/"
# Default primary key field type # Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
@ -145,3 +153,6 @@ REST_FRAMEWORK = {
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
] ]
} }
# User model
AUTH_USER_MODEL = "Palto.User"

View file

@ -15,16 +15,27 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
""" """
from django.contrib import admin from django.contrib import admin
from django.urls import path, include from django.urls import path, include, re_path
from django.views.static import serve
from Palto import settings
urlpatterns = [ urlpatterns = [
# Application # Application
# ... # ...
# API # API
path('rest/', include('rest_framework.urls')), # API REST path('api/', include('rest_framework.urls')), # API REST
# Debug # Debug
path('admin/', admin.site.urls), # Admin page path('admin/', admin.site.urls), # Admin page
path("__debug__/", include("debug_toolbar.urls")), # Debug toolbar path("__debug__/", include("debug_toolbar.urls")), # Debug toolbar
] ]
if settings.DEBUG:
urlpatterns += [
re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
re_path(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATIC_ROOT}),
]

0
Palto/manage.py → manage.py Executable file → Normal file
View file