diff --git a/main/admin.py b/main/admin.py index fd1190f..1213962 100644 --- a/main/admin.py +++ b/main/admin.py @@ -1,25 +1,18 @@ from django.contrib import admin -from main.models import ( - Teacher, - Student, - Staff, - Course, - AcademicYear, - Subject, - NewsEvent, -) - -# Register your models here. +from app.models import Teacher, Student, Staff, Course, AcademicYear, Subject, NewsEvent +@admin.register(Teacher) class TeacherAdmin(admin.ModelAdmin): - list_display = ("first_name", "last_name", "email", "phone", "active_status") - search_fields = ("first_name", "last_name", "email") - list_filter = ("gender", "active_status") + list_display = ("id", "first_name", "last_name", "email", "phone", "active_status") + search_fields = ("first_name", "last_name", "email", "phone") + list_filter = ("active_status", "gender", "group") +@admin.register(Student) class StudentAdmin(admin.ModelAdmin): list_display = ( + "id", "first_name", "last_name", "email", @@ -29,11 +22,13 @@ class StudentAdmin(admin.ModelAdmin): "active_status", ) search_fields = ("first_name", "last_name", "email", "phone") - list_filter = ("gender", "course", "academic_year", "active_status") + list_filter = ("active_status", "gender", "course", "academic_year") +@admin.register(Staff) class StaffAdmin(admin.ModelAdmin): list_display = ( + "id", "first_name", "last_name", "email", @@ -42,37 +37,31 @@ class StaffAdmin(admin.ModelAdmin): "active_status", ) search_fields = ("first_name", "last_name", "email", "phone") - list_filter = ("position", "active_status") + list_filter = ("active_status", "position", "group") +@admin.register(Course) class CourseAdmin(admin.ModelAdmin): - list_display = ("name", "course_type", "duration", "academic_year") + list_display = ("id", "name", "course_type", "duration") search_fields = ("name",) - list_filter = ("course_type", "academic_year") + list_filter = ("course_type",) +@admin.register(AcademicYear) class AcademicYearAdmin(admin.ModelAdmin): - list_display = ("batch",) + list_display = ("id", "batch") search_fields = ("batch",) +@admin.register(Subject) class SubjectAdmin(admin.ModelAdmin): - list_display = ("name", "course", "semester_or_year_number") + list_display = ("id", "name", "course", "semester_or_year_number") search_fields = ("name", "course__name") list_filter = ("course", "semester_or_year_number") +@admin.register(NewsEvent) class NewsEventAdmin(admin.ModelAdmin): - list_display = ("title", "type", "created_at") + list_display = ("id", "title", "type", "created_at") search_fields = ("title", "summary") list_filter = ("type", "created_at") - - -# Register models with custom admin configurations -admin.site.register(Teacher, TeacherAdmin) -admin.site.register(Student, StudentAdmin) -admin.site.register(Staff, StaffAdmin) -admin.site.register(Course, CourseAdmin) -admin.site.register(AcademicYear, AcademicYearAdmin) -admin.site.register(Subject, SubjectAdmin) -admin.site.register(NewsEvent, NewsEventAdmin) diff --git a/main/migrations/0001_initial.py b/main/migrations/0001_initial.py index d41cd0e..c112450 100644 --- a/main/migrations/0001_initial.py +++ b/main/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.4 on 2025-01-06 13:02 +# Generated by Django 5.1.4 on 2025-01-06 16:53 import django.core.validators import django.db.models.deletion @@ -17,14 +17,23 @@ class Migration(migrations.Migration): migrations.CreateModel( name='AcademicYear', fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('batch', models.CharField(max_length=255, unique=True)), ], ), + migrations.CreateModel( + name='Course', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('course_type', models.CharField(choices=[('semester', 'Semester-based'), ('yearly', 'Yearly-based')], max_length=10)), + ('duration', models.PositiveIntegerField()), + ], + ), migrations.CreateModel( name='NewsEvent', fields=[ - ('id', models.BigAutoField(primary_key=True, serialize=False)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(max_length=255)), ('summary', models.TextField()), ('type', models.CharField(choices=[('news', 'News'), ('event', 'Event')], max_length=5)), @@ -34,67 +43,68 @@ class Migration(migrations.Migration): migrations.CreateModel( name='Staff', fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('first_name', models.CharField(max_length=255)), ('last_name', models.CharField(max_length=255)), - ('position', models.CharField(choices=[('clerk', 'Clerk'), ('assistant', 'Assistant'), ('guard', 'Guard')], max_length=255)), - ('address', models.CharField(max_length=255)), ('email', models.EmailField(max_length=255, unique=True)), - ('phone', models.CharField(max_length=15, validators=[django.core.validators.RegexValidator('^\\+?1?\\d{9,15}$', 'Enter a valid phone number.')])), - ('active_status', models.BooleanField(default=True)), + ('phone', models.CharField(max_length=15, validators=[django.core.validators.RegexValidator('^\\+?1?\\d{9,15}$')])), ('username', models.CharField(blank=True, max_length=255, null=True, unique=True)), ('password', models.CharField(max_length=255)), + ('active_status', models.BooleanField(default=True)), + ('position', models.CharField(choices=[('clerk', 'Clerk'), ('assistant', 'Assistant'), ('guard', 'Guard')], max_length=255)), + ('address', models.CharField(max_length=255)), + ('group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='auth.group')), ], - ), - migrations.CreateModel( - name='Course', - fields=[ - ('id', models.BigAutoField(primary_key=True, serialize=False)), - ('name', models.CharField(max_length=100)), - ('course_type', models.CharField(choices=[('semester', 'Semester-based'), ('yearly', 'Yearly-based')], max_length=10)), - ('duration', models.PositiveIntegerField(help_text='Number of semesters or years')), - ('academic_year', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.academicyear')), - ], + options={ + 'abstract': False, + }, ), migrations.CreateModel( name='Student', fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('active_status', models.BooleanField(default=True)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('first_name', models.CharField(max_length=255)), ('last_name', models.CharField(max_length=255)), - ('gender', models.CharField(choices=[('M', 'Male'), ('F', 'Female')], max_length=1)), - ('phone', models.CharField(max_length=10, unique=True, validators=[django.core.validators.RegexValidator('^\\d{10}$', 'Enter a valid 10-digit phone number.')])), ('email', models.EmailField(max_length=255, unique=True)), + ('phone', models.CharField(max_length=15, validators=[django.core.validators.RegexValidator('^\\+?1?\\d{9,15}$')])), ('username', models.CharField(blank=True, max_length=255, null=True, unique=True)), ('password', models.CharField(max_length=255)), - ('academic_year', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.academicyear')), - ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.course')), + ('active_status', models.BooleanField(default=True)), + ('gender', models.CharField(choices=[('M', 'Male'), ('F', 'Female')], max_length=1)), + ('academic_year', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.academicyear')), + ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.course')), + ('group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='auth.group')), ], + options={ + 'abstract': False, + }, ), migrations.CreateModel( name='Subject', fields=[ - ('id', models.BigAutoField(primary_key=True, serialize=False)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=255)), ('semester_or_year_number', models.PositiveIntegerField()), - ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subjects', to='main.course')), + ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subjects', to='app.course')), ], ), migrations.CreateModel( name='Teacher', fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('first_name', models.CharField(max_length=255)), ('last_name', models.CharField(max_length=255)), - ('address', models.CharField(max_length=255)), - ('gender', models.CharField(choices=[('M', 'Male'), ('F', 'Female')], max_length=1)), ('email', models.EmailField(max_length=255, unique=True)), - ('phone', models.CharField(max_length=15, validators=[django.core.validators.RegexValidator('^\\+?1?\\d{9,15}$', 'Enter a valid phone number.')])), - ('active_status', models.BooleanField(default=True)), + ('phone', models.CharField(max_length=15, validators=[django.core.validators.RegexValidator('^\\+?1?\\d{9,15}$')])), ('username', models.CharField(blank=True, max_length=255, null=True, unique=True)), ('password', models.CharField(max_length=255)), + ('active_status', models.BooleanField(default=True)), + ('address', models.CharField(max_length=255)), + ('gender', models.CharField(choices=[('M', 'Male'), ('F', 'Female')], max_length=1)), ('group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='auth.group')), ], + options={ + 'abstract': False, + }, ), ] diff --git a/main/models.py b/main/models.py index b115f17..a62e6d3 100644 --- a/main/models.py +++ b/main/models.py @@ -1,110 +1,68 @@ from django.db import models -import random -from django.core.validators import RegexValidator from django.contrib.auth.models import Group -# Create your models here. +from django.core.validators import RegexValidator +from django.contrib.auth.hashers import make_password +import random -class Teacher(models.Model): - id = models.AutoField(primary_key=True) +class BaseUser(models.Model): first_name = models.CharField(max_length=255) last_name = models.CharField(max_length=255) + email = models.EmailField(max_length=255, unique=True) + phone = models.CharField( + max_length=15, validators=[RegexValidator(r"^\+?1?\d{9,15}$")] + ) + username = models.CharField(max_length=255, unique=True, blank=True, null=True) + password = models.CharField(max_length=255) + active_status = models.BooleanField(default=True) + group = models.ForeignKey(Group, on_delete=models.SET_NULL, null=True, blank=True) + + class Meta: + abstract = True + + def save(self, *args, **kwargs): + if not self.username: + self.username = f"{self.first_name.lower()}_{random.randint(1000, 9999)}" + if self._state.adding or not self.password.startswith("pbkdf2_"): + self.password = make_password(self.password) + super().save(*args, **kwargs) + + def __str__(self): + return f"{self.first_name} {self.last_name}" + + +class Teacher(BaseUser): address = models.CharField(max_length=255) gender = models.CharField(max_length=1, choices=[("M", "Male"), ("F", "Female")]) - email = models.EmailField(max_length=255, unique=True) - phone = models.CharField( - max_length=15, - validators=[RegexValidator(r"^\+?1?\d{9,15}$", "Enter a valid phone number.")], - ) - group = models.ForeignKey(Group, on_delete=models.SET_NULL, null=True, blank=True) - active_status = models.BooleanField(default=True) - username = models.CharField(max_length=255, unique=True, blank=True, null=True) - password = models.CharField(max_length=255) - - def save(self, *args, **kwargs): - if not self.username: - random_number = random.randint(1000, 9999) - self.username = f"{self.first_name.lower()}_{random_number}" - super().save(*args, **kwargs) - - def __str__(self): - return f"{self.first_name} {self.last_name}" -class Student(models.Model): - id = models.AutoField(primary_key=True) - active_status = models.BooleanField(default=True) - first_name = models.CharField(max_length=255) - last_name = models.CharField(max_length=255) +class Student(BaseUser): gender = models.CharField(max_length=1, choices=[("M", "Male"), ("F", "Female")]) - phone = models.CharField( - max_length=10, - unique=True, - validators=[ - RegexValidator(r"^\d{10}$", "Enter a valid 10-digit phone number.") - ], - ) - email = models.EmailField(max_length=255, unique=True) course = models.ForeignKey("Course", on_delete=models.CASCADE) academic_year = models.ForeignKey("AcademicYear", on_delete=models.CASCADE) - username = models.CharField(max_length=255, unique=True, blank=True, null=True) - password = models.CharField(max_length=255) - - def save(self, *args, **kwargs): - if not self.username: - random_number = random.randint(1000, 9999) - self.username = f"{self.first_name.lower()}_{random_number}" - super().save(*args, **kwargs) - - def __str__(self): - return f"{self.first_name} {self.last_name}" -class Staff(models.Model): - id = models.AutoField(primary_key=True) - first_name = models.CharField(max_length=255) - last_name = models.CharField(max_length=255) +class Staff(BaseUser): position = models.CharField( max_length=255, choices=[("clerk", "Clerk"), ("assistant", "Assistant"), ("guard", "Guard")], ) address = models.CharField(max_length=255) - email = models.EmailField(max_length=255, unique=True) - phone = models.CharField( - max_length=15, - validators=[RegexValidator(r"^\+?1?\d{9,15}$", "Enter a valid phone number.")], - ) - active_status = models.BooleanField(default=True) - username = models.CharField(max_length=255, unique=True, blank=True, null=True) - password = models.CharField(max_length=255) - - def save(self, *args, **kwargs): - if not self.username: - random_number = random.randint(1000, 9999) - self.username = f"{self.first_name.lower()}_{random_number}" - super().save(*args, **kwargs) - - def __str__(self): - return f"{self.first_name} {self.last_name}" class Course(models.Model): - id = models.BigAutoField(primary_key=True) - COURSE_TYPE_CHOICES = [ - ("semester", "Semester-based"), - ("yearly", "Yearly-based"), - ] name = models.CharField(max_length=100) - academic_year = models.ForeignKey("AcademicYear", on_delete=models.CASCADE) - course_type = models.CharField(max_length=10, choices=COURSE_TYPE_CHOICES) - duration = models.PositiveIntegerField(help_text="Number of semesters or years") + course_type = models.CharField( + max_length=10, + choices=[("semester", "Semester-based"), ("yearly", "Yearly-based")], + ) + duration = models.PositiveIntegerField() def __str__(self): return self.name class AcademicYear(models.Model): - id = models.AutoField(primary_key=True) batch = models.CharField(max_length=255, unique=True) def __str__(self): @@ -112,7 +70,6 @@ class AcademicYear(models.Model): class Subject(models.Model): - id = models.BigAutoField(primary_key=True) name = models.CharField(max_length=255) course = models.ForeignKey( "Course", on_delete=models.CASCADE, related_name="subjects" @@ -124,22 +81,12 @@ class Subject(models.Model): class NewsEvent(models.Model): - TYPE_CHOICES = [ - ("news", "News"), - ("event", "Event"), - ] - id = models.BigAutoField(primary_key=True) title = models.CharField(max_length=255) summary = models.TextField() - type = models.CharField(max_length=5, choices=TYPE_CHOICES) + type = models.CharField( + max_length=5, choices=[("news", "News"), ("event", "Event")] + ) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"{self.title} ({self.get_type_display()})" - - -USER_CHOICES = [ - ("staff", "Staff"), - ("teacher", "Teacher"), - ("student", "Student"), -]