updates
This commit is contained in:
1 parent
9e119917b6
commit
7c402bfb88
54 files changed
+1639
-5032
No files matched your search
+354
-62
@@ -1,92 +1,384 @@
|
||||
from django.contrib import admin
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
from app.models import (
|
||||
Student,
|
||||
Teacher,
|
||||
AcademicYear,
|
||||
Institute,
|
||||
Course,
|
||||
Subject,
|
||||
Student,
|
||||
Staff,
|
||||
Batch,
|
||||
Attendance,
|
||||
AttendanceReport,
|
||||
LeaveReportStudent,
|
||||
LeaveReportTeacher,
|
||||
FeedbackStudent,
|
||||
FeedbackTeacher,
|
||||
AttendanceRecord,
|
||||
Notice,
|
||||
Routine,
|
||||
StudentRoutine,
|
||||
Staff_leave,
|
||||
Student_Leave,
|
||||
StudentFeedback,
|
||||
CourseTracking,
|
||||
)
|
||||
from django.forms import ModelForm
|
||||
from django.contrib.auth.models import User, Group
|
||||
from django.contrib.auth.admin import UserAdmin, GroupAdmin
|
||||
from app.forms import StaffAdminForm, StudentAdminForm
|
||||
# Register your models here.
|
||||
|
||||
|
||||
@admin.register(LeaveReportStudent)
|
||||
class LeaveReportStudentAdmin(admin.ModelAdmin):
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
return redirect(reverse("student_leave_view"))
|
||||
class CustomAdminSite(admin.AdminSite):
|
||||
def get_app_list(self, request):
|
||||
# Original app list
|
||||
app_list = super().get_app_list(request)
|
||||
|
||||
model_map = {
|
||||
"User": {
|
||||
"group": "Authentication",
|
||||
"group_label": "authentication",
|
||||
},
|
||||
"Group": {
|
||||
"group": "Authentication",
|
||||
"group_label": "authentication",
|
||||
},
|
||||
"Institute": {"group": "Organization", "group_label": "organization"},
|
||||
"Batch": {"group": "Organization", "group_label": "organization"},
|
||||
"Notice": {"group": "Organization", "group_label": "organization"},
|
||||
"Course": {"group": "Organization", "group_label": "organization"},
|
||||
"Subject": {"group": "Organization", "group_label": "organization"},
|
||||
"Student": {"group": "Human Management", "group_label": "human_management"},
|
||||
"Staff": {"group": "Human Management", "group_label": "human_management"},
|
||||
"Routine": {"group": "Human Management", "group_label": "human_management"},
|
||||
"Staff_leave": {"group": "Human Management", "group_label": "human_management"},
|
||||
"Student_Leave": {"group": "Human Management", "group_label": "human_management"},
|
||||
"StudentFeedback": {"group": "Human Management", "group_label": "human_management"},
|
||||
"CourseTracking": {"group": "Human Management", "group_label": "human_management"},
|
||||
"Attendance": {
|
||||
"group": "Human Management",
|
||||
"group_label": "human_management",
|
||||
},
|
||||
}
|
||||
|
||||
grouped_app_list = [{"name": "Main", "app_label": "dashboard", "models": []}]
|
||||
grouped_models = {}
|
||||
|
||||
for app in app_list:
|
||||
for model in app["models"]:
|
||||
model_name = model["object_name"]
|
||||
if model_name in model_map:
|
||||
group = model_map[model_name]["group"]
|
||||
if group not in grouped_models:
|
||||
grouped_models[group] = {
|
||||
"name": group,
|
||||
"app_label": model_map[model_name]["group_label"],
|
||||
"models": [],
|
||||
}
|
||||
grouped_models[group]["models"].append(model)
|
||||
|
||||
grouped_app_list = list(grouped_models.values())
|
||||
|
||||
return grouped_app_list
|
||||
|
||||
|
||||
@admin.register(LeaveReportTeacher)
|
||||
class LeaveReportTeacherAdmin(admin.ModelAdmin):
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
return redirect(reverse("teacher_leave_view"))
|
||||
# Create a custom admin site instance
|
||||
custom_admin_site = CustomAdminSite(name="custom_admin")
|
||||
|
||||
|
||||
@admin.register(FeedbackTeacher)
|
||||
class FeedbackTeacherAdmin(admin.ModelAdmin):
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
return redirect(reverse("teacher_feedback"))
|
||||
@admin.register(Institute, site=custom_admin_site)
|
||||
class InstituteModel(admin.ModelAdmin):
|
||||
list_display = ("id", "name", "address", "phone")
|
||||
search_fields = ("name", "phone")
|
||||
list_filter = ("name", "phone")
|
||||
advanced_filter_fields = ("name", "phone")
|
||||
|
||||
|
||||
@admin.register(FeedbackStudent)
|
||||
class FeedbackStudentAdmin(admin.ModelAdmin):
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
return redirect(reverse("student_feedback_message"))
|
||||
@admin.register(Course, site=custom_admin_site)
|
||||
class CourseModel(admin.ModelAdmin):
|
||||
list_display = ("id", "name", "duration", "duration_type")
|
||||
search_fields = ("name", "duration", "duration_type")
|
||||
list_filter = ("name", "duration", "duration_type")
|
||||
advanced_filter_fields = ("name", "duration", "duration_type")
|
||||
|
||||
|
||||
@admin.register(AcademicYear)
|
||||
class AcademicYearAdmin(admin.ModelAdmin):
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
return redirect(reverse("manage_academicyear"))
|
||||
@admin.register(Batch, site=custom_admin_site)
|
||||
class BatchAdmin(admin.ModelAdmin):
|
||||
list_display = ("name", "start_date", "end_date")
|
||||
search_fields = ("name", "start_date", "end_date")
|
||||
list_filter = ("name", "start_date", "end_date")
|
||||
advanced_filter_fields = ("name", "start_date", "end_date")
|
||||
|
||||
|
||||
@admin.register(Attendance)
|
||||
class AttendanceAdmin(admin.ModelAdmin):
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
return redirect(reverse("admin_view_attendance"))
|
||||
@admin.register(Subject, site=custom_admin_site)
|
||||
class SubjectModel(admin.ModelAdmin):
|
||||
list_display = ("id", "name", "course", "semester_or_year")
|
||||
search_fields = ("name", "course_id", "semester_or_year")
|
||||
list_filter = ("name", "course_id", "semester_or_year")
|
||||
|
||||
|
||||
@admin.register(AttendanceReport)
|
||||
class AttendanceReportAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
|
||||
@admin.register(Student)
|
||||
@admin.register(Student, site=custom_admin_site)
|
||||
class StudentAdmin(admin.ModelAdmin):
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
return redirect(reverse("manage_student"))
|
||||
list_display = ("id", "name", "status", "phone")
|
||||
form = StudentAdminForm
|
||||
search_fields = (
|
||||
"name",
|
||||
"phone",
|
||||
"courses",
|
||||
"gender",
|
||||
"joining_date",
|
||||
)
|
||||
list_filter = (
|
||||
"name",
|
||||
"phone",
|
||||
"courses",
|
||||
"gender",
|
||||
"joining_date",
|
||||
"status",
|
||||
)
|
||||
advanced_filter_fields = (
|
||||
"name",
|
||||
"phone",
|
||||
"courses",
|
||||
"gender",
|
||||
"joining_date",
|
||||
"status",
|
||||
)
|
||||
readonly_fields = ("password",)
|
||||
ordering = ("name",)
|
||||
filter_horizontal = ("groups",)
|
||||
|
||||
def has_view_permission(self, request, obj=None):
|
||||
"""Check if user has view permission"""
|
||||
return request.user.has_perm("app.view_student")
|
||||
|
||||
def has_add_permission(self, request):
|
||||
"""Check if user has add permission"""
|
||||
return request.user.has_perm("app.add_student")
|
||||
|
||||
def has_change_permission(self, request, obj=None):
|
||||
"""Check if user has change permission"""
|
||||
return request.user.has_perm("app.change_student")
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
"""Check if user has delete permission"""
|
||||
return request.user.has_perm("app.delete_student")
|
||||
|
||||
def has_module_permission(self, request):
|
||||
"""Check if user has any permissions for this app"""
|
||||
return request.user.has_module_perms("app")
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
if obj:
|
||||
return self.readonly_fields + ("password",)
|
||||
return self.readonly_fields
|
||||
|
||||
class Media:
|
||||
js = ("js/student_admin.js",)
|
||||
|
||||
|
||||
@admin.register(Teacher)
|
||||
class TeacherAdmin(admin.ModelAdmin):
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
return redirect(reverse("manage_teacher"))
|
||||
@admin.register(Staff, site=custom_admin_site)
|
||||
class StaffAdmin(admin.ModelAdmin):
|
||||
list_display = ["name", "phone", "designation", "joining_date"]
|
||||
form = StaffAdminForm
|
||||
search_fields = (
|
||||
"name",
|
||||
"phone",
|
||||
"monthly_salary",
|
||||
"designation",
|
||||
"joining_date",
|
||||
"gender",
|
||||
)
|
||||
list_filter = (
|
||||
"name",
|
||||
"phone",
|
||||
"designation",
|
||||
"joining_date",
|
||||
"gender",
|
||||
"groups",
|
||||
)
|
||||
advanced_filter_fields = (
|
||||
"name",
|
||||
"phone",
|
||||
"designation",
|
||||
"joining_date",
|
||||
"gender",
|
||||
"groups",
|
||||
)
|
||||
readonly_fields = ("password",)
|
||||
ordering = ("name",)
|
||||
filter_horizontal = ("groups",)
|
||||
|
||||
def has_view_permission(self, request, obj=None):
|
||||
"""Check if user has view permission"""
|
||||
return request.user.has_perm("app.view_staff")
|
||||
|
||||
def has_add_permission(self, request):
|
||||
"""Check if user has add permission"""
|
||||
return request.user.has_perm("app.add_staff")
|
||||
|
||||
def has_change_permission(self, request, obj=None):
|
||||
"""Check if user has change permission"""
|
||||
return request.user.has_perm("app.change_staff")
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
"""Check if user has delete permission"""
|
||||
return request.user.has_perm("app.delete_staff")
|
||||
|
||||
def has_module_permission(self, request):
|
||||
"""Check if user has any permissions for this app"""
|
||||
return request.user.has_module_perms("app")
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
if obj:
|
||||
return self.readonly_fields + ("password",)
|
||||
return self.readonly_fields
|
||||
|
||||
class Media:
|
||||
js = ("js/staff_admin.js",)
|
||||
|
||||
|
||||
@admin.register(Course)
|
||||
class CourseAdmin(admin.ModelAdmin):
|
||||
list_display = ("id", "name", "course_type", "duration", "created_at", "updated_at")
|
||||
search_fields = ("name",)
|
||||
list_filter = ("course_type",)
|
||||
readonly_fields = ("created_at", "updated_at")
|
||||
class AttendanceRecordForm(ModelForm):
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
if not cleaned_data.get("student"):
|
||||
if self.instance and self.instance.pk:
|
||||
cleaned_data["student"] = self.instance.student
|
||||
return cleaned_data
|
||||
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
return redirect(reverse("manage_course"))
|
||||
class Meta:
|
||||
model = AttendanceRecord
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
@admin.register(Subject)
|
||||
class SubjectAdmin(admin.ModelAdmin):
|
||||
list_display = ("id", "name", "course", "duration", "created_at", "updated_at")
|
||||
search_fields = ("name", "course__name")
|
||||
list_filter = ("course__course_type", "course__duration")
|
||||
readonly_fields = ("created_at", "updated_at")
|
||||
class AttendanceRecordInline(admin.TabularInline):
|
||||
model = AttendanceRecord
|
||||
form = AttendanceRecordForm
|
||||
extra = 0
|
||||
can_delete = False # Prevent deletion
|
||||
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
return redirect(reverse("manage_subject"))
|
||||
def get_formset(self, request, obj=None, **kwargs):
|
||||
formset = super().get_formset(request, obj, **kwargs)
|
||||
return formset
|
||||
|
||||
|
||||
@admin.register(Attendance, site=custom_admin_site)
|
||||
class AttendanceAdmin(admin.ModelAdmin):
|
||||
list_display = ["date", "routine", "class_status", "teacher", "teacher_attend"]
|
||||
inlines = [AttendanceRecordInline]
|
||||
search_fields = ("date", "routine__name", "teacher__name")
|
||||
list_filter = ("date", "routine", "teacher")
|
||||
advanced_filter_fields = ("date", "routine", "teacher")
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
is_new = not obj.pk
|
||||
super().save_model(request, obj, form, change)
|
||||
|
||||
if is_new and obj.routine:
|
||||
students = Student.objects.filter(routines__routine=obj.routine).distinct()
|
||||
|
||||
for student in students:
|
||||
AttendanceRecord.objects.create(
|
||||
attendance=obj, student=student, student_attend=False
|
||||
)
|
||||
|
||||
def save_formset(self, request, form, formset, change):
|
||||
instances = formset.save(commit=False)
|
||||
|
||||
# Preserve existing records
|
||||
for instance in instances:
|
||||
if instance.pk and not instance.student_id:
|
||||
original = AttendanceRecord.objects.get(pk=instance.pk)
|
||||
instance.student = original.student
|
||||
instance.save()
|
||||
|
||||
formset.save_m2m()
|
||||
|
||||
class Media:
|
||||
js = ("js/attendance_admin.js",)
|
||||
|
||||
|
||||
@admin.register(Notice, site=custom_admin_site)
|
||||
class NoticeAdmin(admin.ModelAdmin):
|
||||
list_display = ("title", "message", "created_at")
|
||||
search_fields = ("title", "message")
|
||||
list_filter = ("title", "message")
|
||||
advanced_filter_fields = ("title", "message")
|
||||
|
||||
class Media:
|
||||
js = ("js/notice_admin.js",)
|
||||
|
||||
|
||||
class StudentRoutineStackInline(admin.StackedInline):
|
||||
model = StudentRoutine
|
||||
extra = 0
|
||||
|
||||
|
||||
@admin.register(Routine, site=custom_admin_site)
|
||||
class RoutineAdmin(admin.ModelAdmin):
|
||||
inlines = [StudentRoutineStackInline]
|
||||
list_display = ["name", "start_time", "end_time", "teacher"]
|
||||
search_fields = ("name", "start_time", "end_time", "teacher__name")
|
||||
list_filter = ("name", "start_time", "end_time", "teacher")
|
||||
advanced_filter_fields = ("name", "start_time", "end_time", "teacher")
|
||||
|
||||
class Media:
|
||||
js = ("js/multiple_student_hover.js", "js/routine_admin.js")
|
||||
|
||||
|
||||
@admin.register(Staff_leave, site=custom_admin_site)
|
||||
class StaffLeaveAdmin(admin.ModelAdmin):
|
||||
list_display = ('staff', 'date', 'get_status_display', 'created_at')
|
||||
list_filter = ('status', 'date', 'created_at')
|
||||
search_fields = ('staff__name', 'message')
|
||||
readonly_fields = ('created_at', 'updated_at')
|
||||
ordering = ('-created_at',)
|
||||
raw_id_fields = ('staff',)
|
||||
|
||||
|
||||
@admin.register(Student_Leave, site=custom_admin_site)
|
||||
class StudentLeaveAdmin(admin.ModelAdmin):
|
||||
list_display = ('student', 'date', 'get_status_display', 'created_at')
|
||||
list_filter = ('status', 'date', 'created_at')
|
||||
search_fields = ('student__name', 'message')
|
||||
readonly_fields = ('created_at', 'updated_at')
|
||||
ordering = ('-created_at',)
|
||||
raw_id_fields = ('student',)
|
||||
|
||||
|
||||
@admin.register(StudentFeedback, site=custom_admin_site)
|
||||
class StudentFeedbackAdmin(admin.ModelAdmin):
|
||||
list_display = ('student', 'rating', 'created_at')
|
||||
list_filter = ('rating', 'created_at')
|
||||
search_fields = ('student__name', 'feedback_text')
|
||||
readonly_fields = ('created_at', 'updated_at')
|
||||
ordering = ('-created_at',)
|
||||
|
||||
|
||||
@admin.register(CourseTracking, site=custom_admin_site)
|
||||
class CourseTrackingAdmin(admin.ModelAdmin):
|
||||
list_display = ('student', 'course', 'progress_status', 'completion_percentage', 'start_date', 'expected_end_date')
|
||||
list_filter = ('progress_status', 'course', 'start_date', 'expected_end_date')
|
||||
search_fields = ('student__name', 'course__name', 'notes')
|
||||
readonly_fields = ('enrollment_date', 'created_at', 'updated_at')
|
||||
ordering = ('-created_at',)
|
||||
raw_id_fields = ('student', 'course')
|
||||
list_per_page = 25
|
||||
|
||||
def has_view_permission(self, request, obj=None):
|
||||
return request.user.has_perm("app.view_coursetracking")
|
||||
|
||||
def has_add_permission(self, request):
|
||||
return request.user.has_perm("app.add_coursetracking")
|
||||
|
||||
def has_change_permission(self, request, obj=None):
|
||||
return request.user.has_perm("app.change_coursetracking")
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return request.user.has_perm("app.delete_coursetracking")
|
||||
|
||||
def has_module_permission(self, request):
|
||||
return request.user.has_module_perms("app")
|
||||
|
||||
class Media:
|
||||
js = ("js/course_tracking_admin.js",)
|
||||
|
||||
|
||||
|
||||
|
||||
custom_admin_site.register(User, UserAdmin)
|
||||
custom_admin_site.register(Group, GroupAdmin)
|
||||
@@ -1,724 +0,0 @@
|
||||
import json
|
||||
import requests
|
||||
from django.contrib.admin import site
|
||||
from django.contrib import messages
|
||||
from django.core.files.storage import FileSystemStorage
|
||||
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.urls import reverse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from app.models import (
|
||||
Student,
|
||||
Teacher,
|
||||
Subject,
|
||||
Course,
|
||||
LeaveReportStudent,
|
||||
LeaveReportTeacher,
|
||||
Attendance,
|
||||
AttendanceReport,
|
||||
AcademicYear,
|
||||
FeedbackStudent,
|
||||
FeedbackTeacher,
|
||||
)
|
||||
from django.contrib.auth.decorators import login_required, user_passes_test
|
||||
from app.forms import SubjectForm
|
||||
|
||||
admin_site = site
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(lambda u: u.is_superuser)
|
||||
def admin_home(request):
|
||||
student_count1 = Student.objects.all().count()
|
||||
teacher_count = Teacher.objects.all().count()
|
||||
subject_count = Subject.objects.all().count()
|
||||
course_count = Course.objects.all().count()
|
||||
course_all = Course.objects.all()
|
||||
course_name_list = []
|
||||
subject_count_list = []
|
||||
student_count_list_in_course = []
|
||||
for course in course_all:
|
||||
subjects = Subject.objects.filter(course_id=course.id).count()
|
||||
students = Student.objects.filter(course_id=course.id).count()
|
||||
course_name_list.append(course.name)
|
||||
subject_count_list.append(subjects)
|
||||
student_count_list_in_course.append(students)
|
||||
|
||||
# subjects_all = Subject.objects.all()
|
||||
# subject_list = []
|
||||
# student_count_list_in_subject = []
|
||||
# for subject in subjects_all:
|
||||
# course = subject.course
|
||||
# student_count = Student.objects.filter(course_id=course.id).count()
|
||||
# subject_list.append(subject.name)
|
||||
# student_count_list_in_subject.append(student_count)
|
||||
|
||||
# teacher = Teacher.objects.all()
|
||||
# attendance_present_list_teacher = []
|
||||
# attendance_absent_list_teacher = []
|
||||
# teacher_name_list = []
|
||||
# for teacher in teacher:
|
||||
# subject_ids = Subject.objects.filter(teacher=teacher).values_list(
|
||||
# "id", flat=True
|
||||
# )
|
||||
# attendance = Attendance.objects.filter(
|
||||
# subject_id__in=subject_ids,
|
||||
# ).count()
|
||||
# leaves = LeaveReportTeacher.objects.filter(
|
||||
# teacher_id=teacher.id, leave_status=1
|
||||
# ).count()
|
||||
# attendance_present_list_teacher.append(attendance)
|
||||
# attendance_absent_list_teacher.append(leaves)
|
||||
# teacher_name_list.append(teacher.first_name)
|
||||
|
||||
# students_all = Student.objects.all()
|
||||
# attendance_present_list_student = []
|
||||
# attendance_absent_list_student = []
|
||||
# student_name_list = []
|
||||
# for student in students_all:
|
||||
# attendance = AttendanceReport.objects.filter(
|
||||
# student_id=student.id, status=True
|
||||
# ).count()
|
||||
# absent = AttendanceReport.objects.filter(
|
||||
# student_id=student.id, status=False
|
||||
# ).count()
|
||||
# leaves = LeaveReportStudent.objects.filter(
|
||||
# student_id=student.id, leave_status=1
|
||||
# ).count()
|
||||
# attendance_present_list_student.append(attendance)
|
||||
# attendance_absent_list_student.append(leaves + absent)
|
||||
# student_name_list.append(student.username)
|
||||
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Admin Dashboard",
|
||||
"student_count": student_count1,
|
||||
"teacher_count": teacher_count,
|
||||
"subject_count": subject_count,
|
||||
"course_count": course_count,
|
||||
# "course_name_list": course_name_list,
|
||||
"subject_count_list": subject_count_list,
|
||||
# "student_count_list_in_course": student_count_list_in_course,
|
||||
# "student_count_list_in_subject": student_count_list_in_subject,
|
||||
# "subject_list": subject_list,
|
||||
# "teacher_name_list": teacher_name_list,
|
||||
# "attendance_present_list_teacher": attendance_present_list_teacher,
|
||||
# "attendance_absent_list_teacher": attendance_absent_list_teacher,
|
||||
# "student_name_list": student_name_list,
|
||||
# "attendance_present_list_student": attendance_present_list_student,
|
||||
# "attendance_absent_list_student": attendance_absent_list_student,
|
||||
"opts": Student._meta,
|
||||
}
|
||||
return render(request, "hod/dashboard.html", context)
|
||||
|
||||
|
||||
def add_course(request):
|
||||
admin_site = site
|
||||
if request.method == "POST":
|
||||
name = request.POST.get("name")
|
||||
course_type = request.POST.get("course_type")
|
||||
duration = request.POST.get("duration")
|
||||
|
||||
if not name or not course_type or not duration:
|
||||
messages.error(request, "All fields are required!")
|
||||
return redirect("add_course")
|
||||
|
||||
try:
|
||||
duration = int(duration)
|
||||
if duration <= 0:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
messages.error(request, "Duration must be a positive number!")
|
||||
return redirect("add_course")
|
||||
|
||||
if Course.objects.filter(name=name).exists():
|
||||
messages.error(request, "A course with this name already exists.")
|
||||
return redirect("add_course")
|
||||
|
||||
Course.objects.create(name=name, course_type=course_type, duration=duration)
|
||||
messages.success(request, "Course added successfully!")
|
||||
return redirect("add_course")
|
||||
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Add Course",
|
||||
"COURSE_TYPE_CHOICES": Course.COURSE_TYPE_CHOICES,
|
||||
"opts": Course._meta,
|
||||
}
|
||||
return render(request, "hod/add_course.html", context)
|
||||
|
||||
|
||||
def manage_course(request):
|
||||
courses = Course.objects.all()
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"courses": courses,
|
||||
"title": "Manage Courses",
|
||||
"opts": Course._meta,
|
||||
}
|
||||
return render(request, "hod/manage_course.html", context)
|
||||
|
||||
|
||||
def edit_course(request, course_id):
|
||||
course = get_object_or_404(Course, id=course_id)
|
||||
|
||||
if request.method == "POST":
|
||||
name = request.POST.get("name")
|
||||
course_type = request.POST.get("course_type")
|
||||
duration = request.POST.get("duration")
|
||||
|
||||
# Validate unique name if it changed
|
||||
if name != course.name and Course.objects.filter(name=name).exists():
|
||||
messages.error(request, "A course with this name already exists.")
|
||||
return render(
|
||||
request, "edit_course.html", {"course": course, "title": "Edit Course"}
|
||||
)
|
||||
|
||||
try:
|
||||
course.name = name
|
||||
course.course_type = course_type
|
||||
course.duration = duration
|
||||
course.save()
|
||||
|
||||
messages.success(request, "Course updated successfully.")
|
||||
return redirect("manage_course")
|
||||
|
||||
except Exception as e:
|
||||
messages.error(request, f"Error updating course: {str(e)}")
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Edit Course",
|
||||
"course": course,
|
||||
}
|
||||
return render(request, "hod/edit_course.html", context)
|
||||
|
||||
|
||||
def delete_course(request, course_id):
|
||||
course = Course.objects.get(id=course_id)
|
||||
try:
|
||||
course.delete()
|
||||
messages.success(request, "Course Deleted Successfully.")
|
||||
return redirect("manage_course")
|
||||
except:
|
||||
messages.error(request, "Failed to Delete Course.")
|
||||
return redirect("manage_course")
|
||||
|
||||
|
||||
def add_academicyear(request):
|
||||
if request.method == "POST":
|
||||
start_date = request.POST.get("start_date")
|
||||
academic_year = AcademicYear.objects.create(start_date=start_date)
|
||||
messages.success(request, "Academic Year added successfully.")
|
||||
return redirect("manage_academicyear")
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Add Academic Year",
|
||||
# "academic_year": academic_year,
|
||||
"opts": AcademicYear._meta,
|
||||
}
|
||||
return render(request, "hod/add_academicyear.html", context)
|
||||
|
||||
|
||||
def edit_academicyear(request, pk):
|
||||
academic_year = get_object_or_404(AcademicYear, pk=pk)
|
||||
if request.method == "POST":
|
||||
start_date = request.POST.get("start_date")
|
||||
|
||||
if start_date:
|
||||
academic_year.start_date = start_date
|
||||
academic_year.save()
|
||||
messages.success(request, "Academic Year updated successfully.")
|
||||
return redirect("manage_academicyear")
|
||||
else:
|
||||
messages.error(request, "Please provide a valid start date.")
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Edit Academic Year",
|
||||
"opts": AcademicYear._meta,
|
||||
}
|
||||
return render(request, "hod/edit_academicyear.html", context)
|
||||
|
||||
|
||||
def manage_academicyear(request):
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"academic_years": AcademicYear.objects.all(),
|
||||
"title": "Manage Academic Year",
|
||||
"opts": AcademicYear._meta,
|
||||
}
|
||||
return render(request, "hod/manage_academicyear.html", context)
|
||||
|
||||
|
||||
def delete_academicyear(request, academic_year_id):
|
||||
academic_year = AcademicYear.objects.get(id=academic_year_id)
|
||||
try:
|
||||
academic_year.delete()
|
||||
messages.success(request, "AcademicYear Deleted Successfully.")
|
||||
return redirect("manage_academicyear")
|
||||
except:
|
||||
messages.error(request, "Failed to Delete AcademicYear.")
|
||||
return redirect("manage_academicyear")
|
||||
|
||||
|
||||
def manage_subjects(request):
|
||||
subjects = Subject.objects.all()
|
||||
courses = Course.objects.all()
|
||||
selected_course_id = request.GET.get("course")
|
||||
selected_duration = request.GET.get("duration", "")
|
||||
|
||||
if selected_course_id and selected_duration:
|
||||
subjects = Subject.objects.filter(
|
||||
course_id=selected_course_id, duration=selected_duration
|
||||
)
|
||||
elif selected_course_id:
|
||||
subjects = Subject.objects.filter(course_id=selected_course_id)
|
||||
elif selected_duration:
|
||||
subjects = Subject.objects.filter(duration=selected_duration)
|
||||
else:
|
||||
subjects = Subject.objects.all()
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"subjects": subjects,
|
||||
"selected_course_id": selected_course_id,
|
||||
"selected_duration": selected_duration,
|
||||
"title": "Manage Subjects",
|
||||
"courses": courses,
|
||||
"opts": Subject._meta,
|
||||
}
|
||||
return render(request, "hod/manage_subject.html", context)
|
||||
|
||||
|
||||
def add_subject(request):
|
||||
courses = Course.objects.all()
|
||||
if request.method == "POST":
|
||||
form = SubjectForm(request.POST)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
return redirect("manage_subjects")
|
||||
else:
|
||||
form = SubjectForm()
|
||||
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Add Subject",
|
||||
"courses": courses,
|
||||
"form": form,
|
||||
"opts": Subject._meta,
|
||||
}
|
||||
return render(request, "hod/add_subject.html", context)
|
||||
|
||||
|
||||
def edit_subject(request, pk):
|
||||
subject = get_object_or_404(Subject, pk=pk)
|
||||
courses = Course.objects.all()
|
||||
if request.method == "POST":
|
||||
form = SubjectForm(request.POST, instance=subject)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
return redirect("manage_subject")
|
||||
else:
|
||||
form = SubjectForm(instance=subject)
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Add Subject",
|
||||
"courses": courses,
|
||||
"form": form,
|
||||
"opts": Subject._meta,
|
||||
}
|
||||
|
||||
return render(request, "hod/edit_subject.html", context)
|
||||
|
||||
|
||||
def delete_subject(request, subject_id):
|
||||
subject = Subject.objects.get(id=subject_id)
|
||||
try:
|
||||
subject.delete()
|
||||
messages.success(request, "Subject Deleted Successfully.")
|
||||
return redirect("manage_subject")
|
||||
except:
|
||||
messages.error(request, "Failed to Delete Subject.")
|
||||
return redirect("manage_subject")
|
||||
|
||||
|
||||
def manage_student(request):
|
||||
search_query = request.GET.get("search", "")
|
||||
students = Student.objects.all()
|
||||
|
||||
if search_query:
|
||||
students = (
|
||||
students.filter(first_name__icontains=search_query)
|
||||
| students.filter(last_name__icontains=search_query)
|
||||
| students.filter(email__icontains=search_query)
|
||||
)
|
||||
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Manage Students",
|
||||
"students": students,
|
||||
"search_query": search_query,
|
||||
}
|
||||
return render(request, "hod/manage_student.html", context)
|
||||
|
||||
|
||||
def add_student(request):
|
||||
courses = Course.objects.all()
|
||||
academic_years = AcademicYear.objects.all()
|
||||
occupation_choices = dict(Student.occupation_choice)
|
||||
relationship_choices = dict(Student.relationship_choice)
|
||||
|
||||
if request.method == "POST":
|
||||
first_name = request.POST.get("first_name")
|
||||
middle_name = request.POST.get("middle_name")
|
||||
last_name = request.POST.get("last_name")
|
||||
email = request.POST.get("email")
|
||||
phone = request.POST.get("phone")
|
||||
dob = request.POST.get("dob")
|
||||
gender = request.POST.get("gender")
|
||||
course_id = request.POST.get("course")
|
||||
academic_year_id = request.POST.get("academic_year")
|
||||
address = request.POST.get("address")
|
||||
father_name = request.POST.get("father_name")
|
||||
father_occupation = request.POST.get("father_occupation")
|
||||
mother_name = request.POST.get("mother_name")
|
||||
mother_occupation = request.POST.get("mother_occupation")
|
||||
guardian_name = request.POST.get("guardian_name")
|
||||
guardian_number = request.POST.get("guardian_number")
|
||||
parents_number = request.POST.get("parents_number")
|
||||
relationship_with_student = request.POST.get("relationship_with_student")
|
||||
|
||||
try:
|
||||
course = get_object_or_404(Course, id=course_id)
|
||||
academic_year = get_object_or_404(AcademicYear, id=academic_year_id)
|
||||
|
||||
Student.objects.create(
|
||||
first_name=first_name,
|
||||
middle_name=middle_name,
|
||||
last_name=last_name,
|
||||
email=email,
|
||||
phone=phone,
|
||||
dob=dob,
|
||||
gender=gender,
|
||||
course=course,
|
||||
academic_year=academic_year,
|
||||
address=address,
|
||||
father_name=father_name,
|
||||
father_occupation=father_occupation,
|
||||
mother_name=mother_name,
|
||||
mother_occupation=mother_occupation,
|
||||
guardian_name=guardian_name,
|
||||
guardian_number=guardian_number,
|
||||
parents_number=parents_number,
|
||||
relationship_with_student=relationship_with_student,
|
||||
)
|
||||
messages.success(request, "Student added successfully!")
|
||||
return redirect("manage_student")
|
||||
except Exception as e:
|
||||
messages.error(request, f"Error adding student: {e}")
|
||||
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Add Student",
|
||||
"courses": courses,
|
||||
"academic_years": academic_years,
|
||||
"occupation_choices": occupation_choices.items(),
|
||||
"relationship_choices": relationship_choices.items(),
|
||||
}
|
||||
return render(request, "hod/add_student.html", context)
|
||||
|
||||
|
||||
def edit_student(request, student_id):
|
||||
student = get_object_or_404(Student, id=student_id)
|
||||
courses = Course.objects.all()
|
||||
academic_years = AcademicYear.objects.all()
|
||||
occupation_choices = dict(Student.occupation_choice)
|
||||
relationship_choices = dict(Student.relationship_choice)
|
||||
|
||||
if request.method == "POST":
|
||||
student.first_name = request.POST.get("first_name")
|
||||
student.middle_name = request.POST.get("middle_name")
|
||||
student.last_name = request.POST.get("last_name")
|
||||
student.email = request.POST.get("email")
|
||||
student.phone = request.POST.get("phone")
|
||||
student.dob = request.POST.get("dob")
|
||||
student.gender = request.POST.get("gender")
|
||||
student.course = get_object_or_404(Course, id=request.POST.get("course"))
|
||||
student.academic_year = get_object_or_404(
|
||||
AcademicYear, id=request.POST.get("academic_year")
|
||||
)
|
||||
student.father_occupation = request.POST.get("father_occupation")
|
||||
student.relationship_with_student = request.POST.get(
|
||||
"relationship_with_student"
|
||||
)
|
||||
|
||||
try:
|
||||
student.save()
|
||||
messages.success(request, "Student updated successfully!")
|
||||
return redirect("manage_student")
|
||||
except Exception as e:
|
||||
messages.error(request, f"Error updating student: {e}")
|
||||
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Edit Student",
|
||||
"student": student,
|
||||
"courses": courses,
|
||||
"academic_years": academic_years,
|
||||
"occupation_choices": occupation_choices.items(),
|
||||
"relationship_choices": relationship_choices.items(),
|
||||
}
|
||||
return render(request, "hod/edit_student.html", context)
|
||||
|
||||
|
||||
def delete_student(request, student_id):
|
||||
student = get_object_or_404(Student, id=student_id)
|
||||
student.delete()
|
||||
messages.success(request, "Student deleted successfully!")
|
||||
return redirect("manage_student")
|
||||
|
||||
|
||||
def manage_teacher(request):
|
||||
teachers = Teacher.objects.all()
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Manage Teachers",
|
||||
"teachers": teachers,
|
||||
}
|
||||
return render(request, "hod/manage_teacher.html", context)
|
||||
|
||||
|
||||
def add_teacher(request):
|
||||
if request.method == "POST":
|
||||
try:
|
||||
Teacher.objects.create(
|
||||
first_name=request.POST.get("first_name"),
|
||||
middle_name=request.POST.get("middle_name"),
|
||||
last_name=request.POST.get("last_name"),
|
||||
email=request.POST.get("email"),
|
||||
phone=request.POST.get("phone"),
|
||||
dob=request.POST.get("dob"),
|
||||
gender=request.POST.get("gender"),
|
||||
address=request.POST.get("address"),
|
||||
# username=request.POST.get("username"),
|
||||
# password=request.POST.get("password"),
|
||||
qualification=request.POST.get("qualification"),
|
||||
specialization_on=request.POST.get("specialization_on"),
|
||||
marital_status=request.POST.get("marital_status"),
|
||||
date_of_joining=request.POST.get("date_of_joining"),
|
||||
)
|
||||
messages.success(request, "Teacher added successfully!")
|
||||
return redirect("manage_teacher")
|
||||
except Exception as e:
|
||||
messages.error(request, f"Error adding teacher: {e}")
|
||||
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Add Teacher",
|
||||
"qualification_choices": dict(Teacher.qualification_choice).items(),
|
||||
"marital_status_choices": dict(Teacher.marital_status_choice).items(),
|
||||
}
|
||||
return render(request, "hod/add_teacher.html", context)
|
||||
|
||||
|
||||
def edit_teacher(request, teacher_id):
|
||||
teacher = get_object_or_404(Teacher, id=teacher_id)
|
||||
|
||||
if request.method == "POST":
|
||||
try:
|
||||
teacher.first_name = request.POST.get("first_name")
|
||||
teacher.middle_name = request.POST.get("middle_name")
|
||||
teacher.last_name = request.POST.get("last_name")
|
||||
teacher.email = request.POST.get("email")
|
||||
teacher.phone = request.POST.get("phone")
|
||||
teacher.dob = request.POST.get("dob")
|
||||
teacher.gender = request.POST.get("gender")
|
||||
teacher.address = request.POST.get("address")
|
||||
teacher.qualification = request.POST.get("qualification")
|
||||
teacher.specialization_on = request.POST.get("specialization_on")
|
||||
teacher.marital_status = request.POST.get("marital_status")
|
||||
teacher.date_of_joining = request.POST.get("date_of_joining")
|
||||
teacher.save()
|
||||
|
||||
messages.success(request, "Teacher updated successfully!")
|
||||
return redirect("manage_teacher")
|
||||
except Exception as e:
|
||||
messages.error(request, f"Error updating teacher: {e}")
|
||||
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Edit Teacher",
|
||||
"teacher": teacher,
|
||||
"qualification_choices": dict(Teacher.qualification_choice).items(),
|
||||
"marital_status_choices": dict(Teacher.marital_status_choice).items(),
|
||||
}
|
||||
return render(request, "hod/edit_teacher.html", context)
|
||||
|
||||
|
||||
def delete_teacher(request, teacher_id):
|
||||
teacher = get_object_or_404(Teacher, id=teacher_id)
|
||||
teacher.delete()
|
||||
messages.success(request, "Teacher deleted successfully!")
|
||||
return redirect("manage_teacher")
|
||||
|
||||
|
||||
def student_feedback_message(request):
|
||||
feedbacks = FeedbackStudent.objects.all()
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Student's Feedback",
|
||||
"feedbacks": feedbacks,
|
||||
}
|
||||
return render(request, "hod/student_feedback.html", context)
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def student_feedback_message_reply(request):
|
||||
feedback_id = request.POST.get("id")
|
||||
feedback_reply = request.POST.get("reply")
|
||||
|
||||
try:
|
||||
feedback = FeedbackStudent.objects.get(id=feedback_id)
|
||||
feedback.feedback_reply = feedback_reply
|
||||
feedback.save()
|
||||
return HttpResponse("True")
|
||||
|
||||
except:
|
||||
return HttpResponse("False")
|
||||
|
||||
|
||||
def teacher_feedback(request):
|
||||
feedbacks = FeedbackTeacher.objects.all()
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Staff's Feedback",
|
||||
"feedbacks": feedbacks,
|
||||
}
|
||||
return render(request, "hod/teacher_feedback.html", context)
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def teacher_feedback_replied(request):
|
||||
feedback_id = request.POST.get("id")
|
||||
feedback_message = request.POST.get("message")
|
||||
|
||||
try:
|
||||
feedback = FeedbackTeacher.objects.get(id=feedback_id)
|
||||
feedback.feedback_reply = feedback_message
|
||||
feedback.save()
|
||||
return HttpResponse("True")
|
||||
except Exception:
|
||||
return HttpResponse("False")
|
||||
|
||||
|
||||
def student_leave_view(request):
|
||||
leaves = LeaveReportStudent.objects.all()
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Student Application",
|
||||
"leaves": leaves,
|
||||
}
|
||||
return render(request, "hod/student_leave_view.html", context)
|
||||
|
||||
|
||||
def student_leave_approve(request, leave_id):
|
||||
leave = LeaveReportStudent.objects.get(id=leave_id)
|
||||
leave.leave_status = 1
|
||||
leave.save()
|
||||
return HttpResponseRedirect(reverse("student_leave_view"))
|
||||
|
||||
|
||||
def student_leave_reject(request, leave_id):
|
||||
leave = LeaveReportStudent.objects.get(id=leave_id)
|
||||
leave.leave_status = 2
|
||||
leave.save()
|
||||
return HttpResponseRedirect(reverse("student_leave_view"))
|
||||
|
||||
|
||||
def teacher_leave_view(request):
|
||||
leaves = LeaveReportTeacher.objects.all()
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"title": "Teacher Application",
|
||||
"leaves": leaves,
|
||||
}
|
||||
return render(request, "hod/teacher_leave_view.html", context)
|
||||
|
||||
|
||||
def teacher_leave_approve(request, leave_id):
|
||||
leave = LeaveReportTeacher.objects.get(id=leave_id)
|
||||
leave.leave_status = 1
|
||||
leave.save()
|
||||
return HttpResponseRedirect(reverse("teacher_leave_view"))
|
||||
|
||||
|
||||
def teacher_leave_reject(request, leave_id):
|
||||
leave = LeaveReportTeacher.objects.get(id=leave_id)
|
||||
leave.leave_status = 2
|
||||
leave.save()
|
||||
return HttpResponseRedirect(reverse("teacher_leave_view"))
|
||||
|
||||
|
||||
def admin_view_attendance(request):
|
||||
subjects = Subject.objects.all()
|
||||
academic_years = AcademicYear.objects.all()
|
||||
context = {
|
||||
**admin_site.each_context(request),
|
||||
"subjects": subjects,
|
||||
"academic_years": academic_years,
|
||||
}
|
||||
return render(request, "hod/view_attendance.html", context)
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def admin_get_attendance_dates(request):
|
||||
# Getting Values from Ajax POST 'Fetch Student'
|
||||
subject_id = request.POST.get("subject")
|
||||
academic_year = request.POST.get("academic_year_id")
|
||||
|
||||
# Students enroll to Course, Course has Subjects
|
||||
# Getting all data from subject model based on subject_id
|
||||
subject_model = Subject.objects.get(id=subject_id)
|
||||
|
||||
academic_model = AcademicYear.objects.get(id=academic_year)
|
||||
|
||||
# students = Students.objects.filter(course_id=subject_model.course_id, session_year_id=session_model)
|
||||
attendance = Attendance.objects.filter(
|
||||
subject_id=subject_model, academic_year_id=academic_model
|
||||
)
|
||||
|
||||
# Only Passing Student Id and Student Name Only
|
||||
list_data = []
|
||||
|
||||
for attendance_single in attendance:
|
||||
data_small = {
|
||||
"id": attendance_single.id,
|
||||
"attendance_date": str(attendance_single.attendance_date),
|
||||
"academic_year_id": attendance_single.academic_year_id.id,
|
||||
}
|
||||
list_data.append(data_small)
|
||||
|
||||
return JsonResponse(
|
||||
json.dumps(list_data), content_type="application/json", safe=False
|
||||
)
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def admin_get_attendance_student(request):
|
||||
# Getting Values from Ajax POST 'Fetch Student'
|
||||
attendance_date = request.POST.get("attendance_date")
|
||||
attendance = Attendance.objects.get(id=attendance_date)
|
||||
|
||||
attendance_data = AttendanceReport.objects.filter(attendance_id=attendance)
|
||||
# Only Passing Student Id and Student Name Only
|
||||
list_data = []
|
||||
|
||||
for student in attendance_data:
|
||||
data_small = {
|
||||
"id": student.student_id.id,
|
||||
"name": student.student_id.first_name + " " + student.student_id.last_name,
|
||||
"status": student.status,
|
||||
}
|
||||
list_data.append(data_small)
|
||||
|
||||
return JsonResponse(
|
||||
json.dumps(list_data), content_type="application/json", safe=False
|
||||
)
|
||||
+2
-2
@@ -2,5 +2,5 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class AppConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "app"
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'app'
|
||||
@@ -0,0 +1,82 @@
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.backends import ModelBackend
|
||||
from .models import Staff, Student
|
||||
|
||||
class MultiModelBackend(ModelBackend):
|
||||
def authenticate(self, request, username=None, password=None, **kwargs):
|
||||
"""
|
||||
Authenticate the user based on username (phone for Student and Staff) and password.
|
||||
"""
|
||||
if username is None or password is None:
|
||||
return None
|
||||
|
||||
# Try authenticating as Staff
|
||||
try:
|
||||
staff = Staff.objects.get(phone=username)
|
||||
if staff.check_password(password):
|
||||
return staff
|
||||
except Staff.DoesNotExist:
|
||||
pass
|
||||
|
||||
# Try authenticating as Student
|
||||
try:
|
||||
student = Student.objects.get(phone=username)
|
||||
if student.check_password(password):
|
||||
return student
|
||||
except Student.DoesNotExist:
|
||||
pass
|
||||
|
||||
# Return None if no match
|
||||
return None
|
||||
|
||||
def get_user(self, user_id):
|
||||
"""
|
||||
Retrieve a user instance using their ID.
|
||||
"""
|
||||
for model in [Staff, Student]:
|
||||
try:
|
||||
return model.objects.get(pk=user_id)
|
||||
except model.DoesNotExist:
|
||||
continue
|
||||
return None
|
||||
|
||||
def get_group_permissions(self, user_obj, obj=None):
|
||||
"""
|
||||
Return a set of permission strings that the user has through their groups.
|
||||
"""
|
||||
if not user_obj.is_active or user_obj.is_anonymous or obj is not None:
|
||||
return set()
|
||||
|
||||
if isinstance(user_obj, (Staff, Student)):
|
||||
if not hasattr(user_obj, '_group_perm_cache'):
|
||||
perms = set()
|
||||
for group in user_obj.groups.all():
|
||||
perms.update(
|
||||
"%s.%s" % (ct, name)
|
||||
for ct, name in group.permissions.values_list(
|
||||
'content_type__app_label',
|
||||
'codename'
|
||||
)
|
||||
)
|
||||
user_obj._group_perm_cache = perms
|
||||
return user_obj._group_perm_cache
|
||||
else:
|
||||
return super().get_group_permissions(user_obj, obj)
|
||||
|
||||
def get_all_permissions(self, user_obj, obj=None):
|
||||
if not user_obj.is_active or user_obj.is_anonymous or obj is not None:
|
||||
return set()
|
||||
|
||||
if isinstance(user_obj, (Staff, Student)):
|
||||
return self.get_group_permissions(user_obj, obj)
|
||||
else:
|
||||
return super().get_all_permissions(user_obj, obj)
|
||||
|
||||
def has_perm(self, user_obj, perm, obj=None):
|
||||
if not user_obj.is_active:
|
||||
return False
|
||||
|
||||
if isinstance(user_obj, (Staff, Student)):
|
||||
return perm in self.get_all_permissions(user_obj, obj)
|
||||
else:
|
||||
return super().has_perm(user_obj, perm, obj)
|
||||
+45
-17
@@ -1,17 +1,45 @@
|
||||
from django import forms
|
||||
from .models import Subject, Course
|
||||
|
||||
|
||||
class SubjectForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Subject
|
||||
fields = ["name", "course", "duration"] # Include 'name' field here
|
||||
|
||||
# Optionally, you can add custom validation if needed.
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields[
|
||||
"course"
|
||||
].queryset = (
|
||||
Course.objects.all()
|
||||
) # Dynamically set the course queryset if needed
|
||||
from django import forms
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from .models import Staff, Student
|
||||
|
||||
|
||||
class StudentAdminForm(forms.ModelForm):
|
||||
new_password = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.PasswordInput,
|
||||
help_text="Enter a new password if you want to reset it. Leave blank otherwise.",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Student
|
||||
fields = "__all__"
|
||||
|
||||
def save(self, commit=True):
|
||||
student = super().save(commit=False)
|
||||
new_password = self.cleaned_data.get("new_password")
|
||||
if new_password:
|
||||
student.password = make_password(new_password)
|
||||
if commit:
|
||||
student.save()
|
||||
return student
|
||||
|
||||
|
||||
class StaffAdminForm(forms.ModelForm):
|
||||
new_password = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.PasswordInput,
|
||||
help_text="Enter a new password if you want to reset it. Leave blank otherwise.",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Staff
|
||||
fields = "__all__"
|
||||
|
||||
def save(self, commit=True):
|
||||
student = super().save(commit=False)
|
||||
new_password = self.cleaned_data.get("new_password")
|
||||
if new_password:
|
||||
student.password = make_password(new_password)
|
||||
if commit:
|
||||
student.save()
|
||||
return student
|
||||
+246
-173
@@ -1,6 +1,7 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-16 16:52
|
||||
# Generated by Django 5.1.7 on 2025-03-25 17:13
|
||||
|
||||
import django.core.validators
|
||||
import django.contrib.auth.models
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
@@ -8,185 +9,257 @@ class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Student",
|
||||
name='Batch',
|
||||
fields=[
|
||||
("id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("first_name", models.CharField(max_length=255)),
|
||||
(
|
||||
"middle_name",
|
||||
models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
("last_name", models.CharField(max_length=255)),
|
||||
("username", models.CharField(max_length=255)),
|
||||
("password", models.CharField(max_length=255)),
|
||||
(
|
||||
"phone",
|
||||
models.CharField(
|
||||
max_length=10,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator("^\\+?1?\\d{9,15}$")
|
||||
],
|
||||
),
|
||||
),
|
||||
("email", models.EmailField(max_length=255, unique=True)),
|
||||
("dob", models.DateField()),
|
||||
(
|
||||
"gender",
|
||||
models.CharField(
|
||||
choices=[("M", "Male"), ("F", "Female")], max_length=1
|
||||
),
|
||||
),
|
||||
("address", models.CharField(max_length=255)),
|
||||
("father_name", models.CharField(max_length=255)),
|
||||
("mother_name", models.CharField(max_length=255)),
|
||||
(
|
||||
"parents_number",
|
||||
models.CharField(
|
||||
max_length=10,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator("^\\+?1?\\d{9,15}$")
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"father_occupation",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("business", "Business"),
|
||||
("doctor", "Doctor"),
|
||||
("farmer", "Farmer"),
|
||||
("teacher", "teacher"),
|
||||
("public service", "Public Service"),
|
||||
("private service", "Private Service"),
|
||||
("shopkeeper", "Shopkeeper"),
|
||||
("driver", "Driver"),
|
||||
("housewife", "HouseWife"),
|
||||
("worker", "Worker"),
|
||||
("N/A", "N/A"),
|
||||
],
|
||||
default="N/A",
|
||||
max_length=45,
|
||||
),
|
||||
),
|
||||
(
|
||||
"mother_occupation",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("business", "Business"),
|
||||
("doctor", "Doctor"),
|
||||
("farmer", "Farmer"),
|
||||
("teacher", "teacher"),
|
||||
("public service", "Public Service"),
|
||||
("private service", "Private Service"),
|
||||
("shopkeeper", "Shopkeeper"),
|
||||
("driver", "Driver"),
|
||||
("housewife", "HouseWife"),
|
||||
("worker", "Worker"),
|
||||
("N/A", "N/A"),
|
||||
],
|
||||
default="N/A",
|
||||
max_length=45,
|
||||
),
|
||||
),
|
||||
("guardian_name", models.CharField(max_length=255)),
|
||||
(
|
||||
"guardian_number",
|
||||
models.CharField(
|
||||
max_length=10,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator("^\\+?1?\\d{9,15}$")
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"relationship_with_student",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("father", "Father"),
|
||||
("mother", "Mother"),
|
||||
("brother", "Brother"),
|
||||
("sister", "Sister"),
|
||||
("uncle", "Uncle"),
|
||||
("aunt", "Aunt"),
|
||||
("grandfather", "Grandfather"),
|
||||
],
|
||||
max_length=45,
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now_add=True)),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('start_date', models.DateField(blank=True, null=True)),
|
||||
('end_date', models.DateField(blank=True, null=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Batch',
|
||||
'verbose_name_plural': 'Batches',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Course',
|
||||
fields=[
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=500)),
|
||||
('duration', models.IntegerField(blank=True, default=1, null=True)),
|
||||
('duration_type', models.CharField(blank=True, choices=[('Year', 'Yearl Based'), ('Semester', 'Semester Based')], max_length=255, null=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Course',
|
||||
'verbose_name_plural': 'Courses',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FCMDevice',
|
||||
fields=[
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('token', models.TextField(unique=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Teacher",
|
||||
name='Institute',
|
||||
fields=[
|
||||
("id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("first_name", models.CharField(max_length=255)),
|
||||
(
|
||||
"middle_name",
|
||||
models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
("last_name", models.CharField(max_length=255)),
|
||||
(
|
||||
"phone",
|
||||
models.CharField(
|
||||
max_length=10,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator("^\\+?1?\\d{9,15}$")
|
||||
],
|
||||
),
|
||||
),
|
||||
("email", models.EmailField(max_length=255, unique=True)),
|
||||
("dob", models.DateField()),
|
||||
(
|
||||
"gender",
|
||||
models.CharField(
|
||||
choices=[("M", "Male"), ("F", "Female")], max_length=1
|
||||
),
|
||||
),
|
||||
("address", models.CharField(max_length=255)),
|
||||
("username", models.CharField(max_length=255)),
|
||||
("password", models.CharField(max_length=255)),
|
||||
(
|
||||
"qualification",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("BA", "BA"),
|
||||
("BBS", "BBS"),
|
||||
("BE", "BE"),
|
||||
("BEd", "BEd"),
|
||||
("BSc", "BSc"),
|
||||
("MA", "MA"),
|
||||
("MSc", "MSc"),
|
||||
("MBS", "MBS"),
|
||||
("ME", "ME"),
|
||||
("PhD", "PhD"),
|
||||
("Others", "Others"),
|
||||
],
|
||||
max_length=45,
|
||||
),
|
||||
),
|
||||
("specialization", models.CharField(max_length=255)),
|
||||
(
|
||||
"marital_status",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("married", "Married"),
|
||||
("widowed", "Widowed"),
|
||||
("separated", "Separated"),
|
||||
("divorced", "Divorced"),
|
||||
("single", "Single"),
|
||||
],
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
("date_of_joining", models.DateField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now_add=True)),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('phone', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('email', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('address', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('pan_no', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('reg_no', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('logo', models.ImageField(blank=True, null=True, upload_to='image')),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Institute',
|
||||
'verbose_name_plural': 'Institutes',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Notice',
|
||||
fields=[
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('title', models.CharField(max_length=255)),
|
||||
('image', models.ImageField(blank=True, null=True, upload_to='notice')),
|
||||
('message', models.TextField(blank=True, null=True)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Notice',
|
||||
'verbose_name_plural': 'Notices',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Staff',
|
||||
fields=[
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_active', models.BooleanField(default=True)),
|
||||
('is_superuser', models.BooleanField(default=False)),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('phone', models.CharField(blank=True, max_length=255, null=True, unique=True)),
|
||||
('designation', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('gender', models.CharField(blank=True, choices=[('Male', 'Male'), ('Female', 'Female'), ('Other', 'Other')], max_length=255, null=True)),
|
||||
('birth_date', models.DateField(blank=True, null=True)),
|
||||
('email', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('temporary_address', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('permanent_address', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('marital_status', models.CharField(blank=True, choices=[('Married', 'Married'), ('Unmarried', 'Unmarried'), ('Divorced', 'Divorced')], max_length=255, null=True)),
|
||||
('joining_date', models.DateField(blank=True, null=True)),
|
||||
('password', models.CharField(editable=False, max_length=128, null=True)),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this staff belongs to.', related_name='staffs', to='auth.group', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this staff.', related_name='staff_set', related_query_name='staff', to='auth.permission', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Staff',
|
||||
'verbose_name_plural': 'Staffs',
|
||||
},
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Routine',
|
||||
fields=[
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('start_time', models.TimeField(blank=True, null=True)),
|
||||
('end_time', models.TimeField(blank=True, null=True)),
|
||||
('teacher', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='routines', to='app.staff')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Routine',
|
||||
'verbose_name_plural': 'Routines',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Attendance',
|
||||
fields=[
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('date', models.DateField()),
|
||||
('teacher_attend', models.BooleanField(default=True)),
|
||||
('class_status', models.BooleanField(default=True)),
|
||||
('routine', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='attendances', to='app.routine')),
|
||||
('teacher', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='attendances', to='app.staff')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Attendance',
|
||||
'verbose_name_plural': 'Attendances',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Staff_leave',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('date', models.DateField()),
|
||||
('message', models.TextField()),
|
||||
('status', models.IntegerField(choices=[(0, 'Pending'), (1, 'Approved'), (2, 'Rejected')], default=0)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('staff', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.staff')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Staff Leave',
|
||||
'verbose_name_plural': 'Staff Leaves',
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Student',
|
||||
fields=[
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('status', models.CharField(blank=True, choices=[('Active', 'Active'), ('Leave', 'Leave'), ('Completed', 'Completed')], max_length=255, null=True)),
|
||||
('gender', models.CharField(blank=True, choices=[('Male', 'Male'), ('Female', 'Female'), ('Other', 'Other')], max_length=255, null=True)),
|
||||
('birth_date', models.DateField(blank=True, null=True)),
|
||||
('email', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('phone', models.CharField(blank=True, max_length=255, null=True, unique=True)),
|
||||
('temporary_address', models.CharField(blank=True, max_length=500, null=True)),
|
||||
('permanent_address', models.CharField(blank=True, max_length=500, null=True)),
|
||||
('parent_name', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('parent_phone', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('joining_date', models.DateField(blank=True, null=True)),
|
||||
('password', models.CharField(editable=False, max_length=128, null=True)),
|
||||
('courses', models.ManyToManyField(blank=True, related_name='students', to='app.course')),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this student belongs to.', related_name='students', to='auth.group', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this student.', related_name='student_set', related_query_name='student', to='auth.permission', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Student',
|
||||
'verbose_name_plural': 'Students',
|
||||
},
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AttendanceRecord',
|
||||
fields=[
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('student_attend', models.BooleanField(default=False)),
|
||||
('attendance', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='records', to='app.attendance')),
|
||||
('student', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='attendance_records', to='app.student')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Student_Leave',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('date', models.DateField()),
|
||||
('message', models.TextField()),
|
||||
('status', models.IntegerField(choices=[(0, 'Pending'), (1, 'Approved'), (2, 'Rejected')], default=0)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.student')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Student Leave',
|
||||
'verbose_name_plural': 'Student Leaves',
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='StudentRoutine',
|
||||
fields=[
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('course', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='app.course')),
|
||||
('routine', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='students', to='app.routine')),
|
||||
('student', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='routines', to='app.student')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Subject',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('semester_or_year', models.PositiveIntegerField()),
|
||||
('course', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='app.course')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='StudentFeedback',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('rating', models.IntegerField(choices=[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)])),
|
||||
('feedback_text', models.TextField()),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='feedbacks', to='app.student')),
|
||||
('teacher', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.staff')),
|
||||
('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.subject')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Student Feedback',
|
||||
'verbose_name_plural': 'Student Feedbacks',
|
||||
'unique_together': {('student', 'subject', 'teacher')},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TeacherFeedback',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('feedback_text', models.TextField()),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.subject')),
|
||||
('teacher', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='feedbacks', to='app.staff')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Teacher Feedback',
|
||||
'verbose_name_plural': 'Teacher Feedbacks',
|
||||
'unique_together': {('teacher', 'subject')},
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,28 @@
|
||||
# Generated by Django 5.1.7 on 2025-03-25 17:18
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='studentfeedback',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='TeacherFeedback',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='studentfeedback',
|
||||
name='subject',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='studentfeedback',
|
||||
name='teacher',
|
||||
),
|
||||
]
|
||||
@@ -1,40 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-16 16:55
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("app", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="teacher",
|
||||
old_name="specialization",
|
||||
new_name="specialization_on",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="teacher",
|
||||
name="qualification",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("SLC", "SLC"),
|
||||
("Intermediate", "Intermediate"),
|
||||
("BA", "BA"),
|
||||
("BBS", "BBS"),
|
||||
("BE", "BE"),
|
||||
("BEd", "BEd"),
|
||||
("BSc", "BSc"),
|
||||
("MA", "MA"),
|
||||
("MSc", "MSc"),
|
||||
("MBS", "MBS"),
|
||||
("ME", "ME"),
|
||||
("PhD", "PhD"),
|
||||
("Others", "Others"),
|
||||
],
|
||||
max_length=45,
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -1,64 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-16 17:12
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("app", "0002_rename_specialization_teacher_specialization_on_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="AcademicYear",
|
||||
fields=[
|
||||
("id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("start_date", models.DateField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Course",
|
||||
fields=[
|
||||
("id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("name", models.CharField(max_length=255, unique=True)),
|
||||
(
|
||||
"course_type",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("semester", "Semester-based"),
|
||||
("year", "Year-based"),
|
||||
],
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
(
|
||||
"duration",
|
||||
models.PositiveIntegerField(help_text="Duration in months"),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Subject",
|
||||
fields=[
|
||||
("id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("name", models.CharField(max_length=255, unique=True)),
|
||||
("description", models.TextField(blank=True, null=True)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"course",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="subjects",
|
||||
to="app.course",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,37 @@
|
||||
# Generated by Django 5.1.7 on 2025-03-25 18:18
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0002_alter_studentfeedback_unique_together_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CourseTracking',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('enrollment_date', models.DateField(auto_now_add=True)),
|
||||
('start_date', models.DateField(blank=True, null=True)),
|
||||
('expected_end_date', models.DateField(blank=True, null=True)),
|
||||
('actual_end_date', models.DateField(blank=True, null=True)),
|
||||
('progress_status', models.CharField(choices=[('Not Started', 'Not Started'), ('In Progress', 'In Progress'), ('Completed', 'Completed'), ('Dropped', 'Dropped')], default='Not Started', max_length=20)),
|
||||
('completion_percentage', models.IntegerField(default=0, help_text='Percentage of course completion (0-100)')),
|
||||
('notes', models.TextField(blank=True, null=True)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='student_trackings', to='app.course')),
|
||||
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='course_trackings', to='app.student')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Course Tracking',
|
||||
'verbose_name_plural': 'Course Trackings',
|
||||
'ordering': ['-created_at'],
|
||||
'unique_together': {('student', 'course')},
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,34 @@
|
||||
# Generated by Django 5.1.7 on 2025-03-25 18:27
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0003_coursetracking'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='studentfeedback',
|
||||
options={'ordering': ['-created_at'], 'verbose_name': 'Student Feedback', 'verbose_name_plural': 'Student Feedbacks'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='studentfeedback',
|
||||
name='subject',
|
||||
field=models.ForeignKey(default='1', on_delete=django.db.models.deletion.CASCADE, related_name='feedbacks', to='app.subject'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='studentfeedback',
|
||||
name='teacher',
|
||||
field=models.ForeignKey(default='1', on_delete=django.db.models.deletion.CASCADE, related_name='feedbacks', to='app.staff'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='studentfeedback',
|
||||
unique_together={('student', 'subject', 'teacher')},
|
||||
),
|
||||
]
|
||||
@@ -1,26 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-16 17:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("app", "0003_academicyear_course_subject"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="subject",
|
||||
name="description",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="subject",
|
||||
name="duration",
|
||||
field=models.PositiveIntegerField(
|
||||
default="1",
|
||||
help_text="For semester-based courses, specify the semester number. For year-based courses, specify the year.",
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -1,36 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-16 17:35
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("app", "0004_remove_subject_description_subject_duration"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="student",
|
||||
name="academic_year",
|
||||
field=models.ForeignKey(
|
||||
default="1",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="students",
|
||||
to="app.academicyear",
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="student",
|
||||
name="course",
|
||||
field=models.ForeignKey(
|
||||
default="1",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="students",
|
||||
to="app.course",
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -1,57 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-16 17:37
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("app", "0005_student_academic_year_student_course"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Attendance",
|
||||
fields=[
|
||||
("id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("attendance_date", models.DateField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"academic_year",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="app.academicyear",
|
||||
),
|
||||
),
|
||||
(
|
||||
"subject_id",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.DO_NOTHING, to="app.subject"
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="AttendanceReport",
|
||||
fields=[
|
||||
("id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("status", models.BooleanField(default=False)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now_add=True)),
|
||||
(
|
||||
"attendance_id",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="app.attendance"
|
||||
),
|
||||
),
|
||||
(
|
||||
"student_id",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.DO_NOTHING, to="app.student"
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,48 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-16 17:44
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("app", "0006_attendance_attendancereport"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="LeaveReportStudent",
|
||||
fields=[
|
||||
("id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("leave_date", models.CharField(max_length=255)),
|
||||
("leave_message", models.TextField()),
|
||||
("leave_status", models.IntegerField(default=0)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"student_id",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="app.student"
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="LeaveReportTeacher",
|
||||
fields=[
|
||||
("id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("leave_date", models.CharField(max_length=255)),
|
||||
("leave_message", models.TextField()),
|
||||
("leave_status", models.IntegerField(default=0)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"teacher_id",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="app.teacher"
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,56 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-16 17:46
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("app", "0007_leavereportstudent_leavereportteacher"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="leavereportstudent",
|
||||
name="leave_date",
|
||||
field=models.DateField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="leavereportteacher",
|
||||
name="leave_date",
|
||||
field=models.DateField(),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="FeedBackStudent",
|
||||
fields=[
|
||||
("id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("feedback", models.TextField()),
|
||||
("feedback_reply", models.TextField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"student_id",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="app.student"
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="FeedBackTeacher",
|
||||
fields=[
|
||||
("id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("feedback", models.TextField()),
|
||||
("feedback_reply", models.TextField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"staff_id",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="app.teacher"
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,29 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-18 06:51
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("app", "0008_alter_leavereportstudent_leave_date_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="student",
|
||||
name="password",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="student",
|
||||
name="username",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="teacher",
|
||||
name="password",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="teacher",
|
||||
name="username",
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-18 07:59
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("app", "0009_remove_student_password_remove_student_username_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="feedbackstudent",
|
||||
name="feedback_reply",
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-18 09:04
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("app", "0010_alter_feedbackstudent_feedback_reply"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="feedbackteacher",
|
||||
old_name="staff_id",
|
||||
new_name="teacher_id",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="feedbackteacher",
|
||||
name="feedback_reply",
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-18 09:48
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("app", "0011_rename_staff_id_feedbackteacher_teacher_id_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="attendance",
|
||||
old_name="academic_year",
|
||||
new_name="academic_year_id",
|
||||
),
|
||||
]
|
||||
@@ -1,72 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-18 10:24
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("app", "0012_rename_academic_year_attendance_academic_year_id"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="student",
|
||||
name="fcm_token",
|
||||
field=models.TextField(default=""),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="student",
|
||||
name="password",
|
||||
field=models.CharField(default="1", max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="student",
|
||||
name="user",
|
||||
field=models.OneToOneField(
|
||||
default="1",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="student",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="student",
|
||||
name="username",
|
||||
field=models.CharField(default="1", max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="teacher",
|
||||
name="fcm_token",
|
||||
field=models.TextField(default=""),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="teacher",
|
||||
name="password",
|
||||
field=models.CharField(default="1", max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="teacher",
|
||||
name="user",
|
||||
field=models.OneToOneField(
|
||||
default="1",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="teacher",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="teacher",
|
||||
name="username",
|
||||
field=models.CharField(default="1", max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -1,29 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-18 10:39
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("app", "0013_student_fcm_token_student_password_student_user_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="student",
|
||||
name="user",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="student",
|
||||
name="username",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="teacher",
|
||||
name="user",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="teacher",
|
||||
name="username",
|
||||
),
|
||||
]
|
||||
+577
-202
@@ -1,233 +1,608 @@
|
||||
from django.db import models
|
||||
from django.core.validators import RegexValidator, ValidationError
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils import timezone
|
||||
from datetime import date
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from django.core.cache import cache
|
||||
|
||||
# Create your models here.
|
||||
duration_types_choices = (("Year", "Yearl Based"), ("Semester", "Semester Based"))
|
||||
student_status_choices = (
|
||||
("Active", "Active"),
|
||||
("Leave", "Leave"),
|
||||
("Completed", "Completed"),
|
||||
)
|
||||
gender_choices = (("Male", "Male"), ("Female", "Female"), ("Other", "Other"))
|
||||
marital_status_choices = (
|
||||
("Married", "Married"),
|
||||
("Unmarried", "Unmarried"),
|
||||
("Divorced", "Divorced"),
|
||||
)
|
||||
|
||||
|
||||
class Student(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
first_name = models.CharField(max_length=255)
|
||||
middle_name = models.CharField(max_length=255, blank=True, null=True)
|
||||
last_name = models.CharField(max_length=255)
|
||||
course = models.ForeignKey(
|
||||
"Course", on_delete=models.CASCADE, related_name="students"
|
||||
)
|
||||
academic_year = models.ForeignKey(
|
||||
"AcademicYear", on_delete=models.CASCADE, related_name="students"
|
||||
)
|
||||
password = models.CharField(max_length=255)
|
||||
fcm_token = models.TextField(default="")
|
||||
phone = models.CharField(
|
||||
max_length=10, validators=[RegexValidator(r"^\+?1?\d{9,15}$")]
|
||||
)
|
||||
email = models.EmailField(max_length=255, unique=True)
|
||||
dob = models.DateField()
|
||||
gender = models.CharField(max_length=1, choices=[("M", "Male"), ("F", "Female")])
|
||||
address = models.CharField(max_length=255)
|
||||
father_name = models.CharField(max_length=255)
|
||||
mother_name = models.CharField(max_length=255)
|
||||
parents_number = models.CharField(
|
||||
max_length=10, validators=[RegexValidator(r"^\+?1?\d{9,15}$")]
|
||||
)
|
||||
occupation_choice = (
|
||||
("business", "Business"),
|
||||
("doctor", "Doctor"),
|
||||
("farmer", "Farmer"),
|
||||
("teacher", "teacher"),
|
||||
("public service", "Public Service"),
|
||||
("private service", "Private Service"),
|
||||
("shopkeeper", "Shopkeeper"),
|
||||
("driver", "Driver"),
|
||||
("housewife", "HouseWife"),
|
||||
("worker", "Worker"),
|
||||
("N/A", "N/A"),
|
||||
)
|
||||
father_occupation = models.CharField(
|
||||
choices=occupation_choice, max_length=45, default="N/A"
|
||||
)
|
||||
mother_occupation = models.CharField(
|
||||
choices=occupation_choice, max_length=45, default="N/A"
|
||||
)
|
||||
guardian_name = models.CharField(max_length=255)
|
||||
guardian_number = models.CharField(
|
||||
max_length=10, validators=[RegexValidator(r"^\+?1?\d{9,15}$")]
|
||||
)
|
||||
relationship_choice = (
|
||||
("father", "Father"),
|
||||
("mother", "Mother"),
|
||||
("brother", "Brother"),
|
||||
("sister", "Sister"),
|
||||
("uncle", "Uncle"),
|
||||
("aunt", "Aunt"),
|
||||
("grandfather", "Grandfather"),
|
||||
)
|
||||
relationship_with_student = models.CharField(
|
||||
choices=relationship_choice, max_length=45
|
||||
)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
|
||||
class Teacher(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
first_name = models.CharField(max_length=255)
|
||||
middle_name = models.CharField(max_length=255, blank=True, null=True)
|
||||
last_name = models.CharField(max_length=255)
|
||||
phone = models.CharField(
|
||||
max_length=10, validators=[RegexValidator(r"^\+?1?\d{9,15}$")]
|
||||
)
|
||||
email = models.EmailField(max_length=255, unique=True)
|
||||
dob = models.DateField()
|
||||
gender = models.CharField(max_length=1, choices=[("M", "Male"), ("F", "Female")])
|
||||
address = models.CharField(max_length=255)
|
||||
fcm_token = models.TextField(default="")
|
||||
password = models.CharField(max_length=255)
|
||||
qualification_choice = (
|
||||
("SLC", "SLC"),
|
||||
("Intermediate", "Intermediate"),
|
||||
("BA", "BA"),
|
||||
("BBS", "BBS"),
|
||||
("BE", "BE"),
|
||||
("BEd", "BEd"),
|
||||
("BSc", "BSc"),
|
||||
("MA", "MA"),
|
||||
("MSc", "MSc"),
|
||||
("MBS", "MBS"),
|
||||
("ME", "ME"),
|
||||
("PhD", "PhD"),
|
||||
("Others", "Others"),
|
||||
)
|
||||
qualification = models.CharField(choices=qualification_choice, max_length=45)
|
||||
specialization_on = models.CharField(max_length=255)
|
||||
marital_status_choice = (
|
||||
("married", "Married"),
|
||||
("widowed", "Widowed"),
|
||||
("separated", "Separated"),
|
||||
("divorced", "Divorced"),
|
||||
("single", "Single"),
|
||||
)
|
||||
marital_status = models.CharField(choices=marital_status_choice, max_length=10)
|
||||
date_of_joining = models.DateField()
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now_add=True)
|
||||
class Institute(models.Model):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=255)
|
||||
phone = models.CharField(max_length=255, null=True, blank=True)
|
||||
email = models.CharField(max_length=255, null=True, blank=True)
|
||||
address = models.CharField(max_length=255, null=True, blank=True)
|
||||
pan_no = models.CharField(max_length=255, null=True, blank=True)
|
||||
reg_no = models.CharField(max_length=255, null=True, blank=True)
|
||||
logo = models.ImageField(upload_to="image", null=True, blank=True)
|
||||
description = models.TextField(null=True, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.first_name + "" + self.middle_name + "" + self.last_name
|
||||
return self.name
|
||||
|
||||
|
||||
class AcademicYear(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
start_date = models.DateField()
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.start_date)
|
||||
class Meta:
|
||||
verbose_name = "Institute"
|
||||
verbose_name_plural = "Institutes"
|
||||
|
||||
|
||||
class Course(models.Model):
|
||||
SEMESTER = "semester"
|
||||
YEAR = "year"
|
||||
|
||||
COURSE_TYPE_CHOICES = [
|
||||
(SEMESTER, "Semester-based"),
|
||||
(YEAR, "Year-based"),
|
||||
]
|
||||
|
||||
id = models.AutoField(primary_key=True)
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
course_type = models.CharField(max_length=10, choices=COURSE_TYPE_CHOICES)
|
||||
duration = models.PositiveIntegerField(help_text="Duration in months")
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=500)
|
||||
duration = models.IntegerField(default=1, null=True, blank=True)
|
||||
duration_type = models.CharField(
|
||||
max_length=255, choices=duration_types_choices, null=True, blank=True
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.get_course_type_display()})"
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Course"
|
||||
verbose_name_plural = "Courses"
|
||||
|
||||
|
||||
class Subject(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
course = models.ForeignKey(
|
||||
Course, on_delete=models.CASCADE, related_name="subjects"
|
||||
name = models.CharField(max_length=255)
|
||||
course = models.ForeignKey(Course, on_delete=models.CASCADE, default=1)
|
||||
semester_or_year = models.PositiveIntegerField()
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Student(AbstractUser):
|
||||
first_name = None
|
||||
last_name = None
|
||||
is_superuser = None
|
||||
date_joined = None
|
||||
username = None
|
||||
email = None
|
||||
|
||||
user_permissions = models.ManyToManyField(
|
||||
"auth.Permission",
|
||||
verbose_name="user permissions",
|
||||
blank=True,
|
||||
help_text="Specific permissions for this student.",
|
||||
related_name="student_set", # This fixes the clash
|
||||
related_query_name="student",
|
||||
)
|
||||
duration = models.PositiveIntegerField(
|
||||
help_text="For semester-based courses, specify the semester number. For year-based courses, specify the year."
|
||||
|
||||
# Similarly, let's also update groups to be explicit
|
||||
groups = models.ManyToManyField(
|
||||
"auth.Group",
|
||||
verbose_name="groups",
|
||||
blank=True,
|
||||
help_text="The groups this student belongs to.",
|
||||
related_name="students", # This matches your existing related_name
|
||||
)
|
||||
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=255)
|
||||
status = models.CharField(
|
||||
max_length=255, choices=student_status_choices, null=True, blank=True
|
||||
)
|
||||
gender = models.CharField(
|
||||
max_length=255, choices=gender_choices, null=True, blank=True
|
||||
)
|
||||
birth_date = models.DateField(null=True, blank=True)
|
||||
email = models.CharField(max_length=255, null=True, blank=True)
|
||||
phone = models.CharField(max_length=255, null=True, blank=True, unique=True)
|
||||
temporary_address = models.CharField(max_length=500, null=True, blank=True)
|
||||
permanent_address = models.CharField(max_length=500, null=True, blank=True)
|
||||
parent_name = models.CharField(max_length=255, null=True, blank=True)
|
||||
parent_phone = models.CharField(max_length=255, null=True, blank=True)
|
||||
courses = models.ManyToManyField(Course, related_name="students", blank=True)
|
||||
joining_date = models.DateField(null=True, blank=True)
|
||||
password = models.CharField(
|
||||
max_length=128, editable=False, null=True
|
||||
) # Editable is set to False to prevent direct editing
|
||||
|
||||
USERNAME_FIELD = "phone"
|
||||
REQUIRED_FIELDS = ["name"] # Add required fields
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def set_password(self, raw_password):
|
||||
self.password = make_password(raw_password)
|
||||
self.save(update_fields=["password"])
|
||||
|
||||
@property
|
||||
def is_staff(self):
|
||||
"""Check if student has any groups (permissions)"""
|
||||
return self.groups.exists()
|
||||
|
||||
def has_perm(self, perm, obj=None):
|
||||
"""Check if student has a specific permission"""
|
||||
if not self.is_active:
|
||||
return False
|
||||
|
||||
# Get permissions from groups
|
||||
perms = set()
|
||||
for group in self.groups.all():
|
||||
perms.update(
|
||||
group.permissions.values_list("content_type__app_label", "codename")
|
||||
)
|
||||
|
||||
# Convert permission string to app_label and codename
|
||||
app_label, codename = perm.split(".")
|
||||
return (app_label, codename) in perms
|
||||
|
||||
def has_module_perms(self, app_label):
|
||||
"""Check if student has any permissions in the given app"""
|
||||
if not self.is_active:
|
||||
return False
|
||||
|
||||
# Check if any group permissions match the app_label
|
||||
for group in self.groups.all():
|
||||
if group.permissions.filter(content_type__app_label=app_label).exists():
|
||||
return True
|
||||
return False
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Student"
|
||||
verbose_name_plural = "Students"
|
||||
|
||||
|
||||
class Staff(AbstractUser):
|
||||
first_name = None
|
||||
last_name = None
|
||||
date_joined = None
|
||||
username = None
|
||||
email = None
|
||||
is_active = models.BooleanField(default=True)
|
||||
is_staff = models.BooleanField(default=True)
|
||||
is_superuser = models.BooleanField(default=False)
|
||||
|
||||
user_permissions = models.ManyToManyField(
|
||||
"auth.Permission",
|
||||
verbose_name="user permissions",
|
||||
blank=True,
|
||||
help_text="Specific permissions for this staff.",
|
||||
related_name="staff_set", # This fixes the clash
|
||||
related_query_name="staff",
|
||||
)
|
||||
|
||||
# Similarly, let's also update groups to be explicit
|
||||
groups = models.ManyToManyField(
|
||||
"auth.Group",
|
||||
verbose_name="groups",
|
||||
blank=True,
|
||||
help_text="The groups this staff belongs to.",
|
||||
related_name="staffs", # This matches your existing related_name
|
||||
)
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=255)
|
||||
phone = models.CharField(max_length=255, null=True, blank=True, unique=True)
|
||||
designation = models.CharField(max_length=255, null=True, blank=True)
|
||||
gender = models.CharField(
|
||||
max_length=255, choices=gender_choices, null=True, blank=True
|
||||
)
|
||||
birth_date = models.DateField(null=True, blank=True)
|
||||
email = models.CharField(max_length=255, null=True, blank=True)
|
||||
temporary_address = models.CharField(max_length=255, null=True, blank=True)
|
||||
permanent_address = models.CharField(max_length=255, null=True, blank=True)
|
||||
marital_status = models.CharField(
|
||||
max_length=255, choices=marital_status_choices, null=True, blank=True
|
||||
)
|
||||
joining_date = models.DateField(null=True, blank=True)
|
||||
password = models.CharField(
|
||||
max_length=128, editable=False, null=True
|
||||
) # Editable is set to False to prevent direct editing
|
||||
|
||||
USERNAME_FIELD = "phone"
|
||||
REQUIRED_FIELDS = ["name"] # Add required fields
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def set_password(self, raw_password):
|
||||
self.password = make_password(raw_password)
|
||||
self.save(update_fields=["password"])
|
||||
|
||||
@property
|
||||
def is_staff(self):
|
||||
"""Check if student has any groups (permissions)"""
|
||||
return True
|
||||
|
||||
@property
|
||||
def is_authenticated(self):
|
||||
return True
|
||||
|
||||
def has_perm(self, perm, obj=None):
|
||||
"""Check if student has a specific permission"""
|
||||
if not self.is_active:
|
||||
return False
|
||||
|
||||
# Get permissions from groups
|
||||
perms = set()
|
||||
for group in self.groups.all():
|
||||
perms.update(
|
||||
group.permissions.values_list("content_type__app_label", "codename")
|
||||
)
|
||||
|
||||
# Convert permission string to app_label and codename
|
||||
app_label, codename = perm.split(".")
|
||||
return (app_label, codename) in perms
|
||||
|
||||
def has_module_perms(self, app_label):
|
||||
"""Check if student has any permissions in the given app"""
|
||||
if not self.is_active:
|
||||
return False
|
||||
|
||||
# Check if any group permissions match the app_label
|
||||
for group in self.groups.all():
|
||||
if group.permissions.filter(content_type__app_label=app_label).exists():
|
||||
return True
|
||||
return False
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Staff"
|
||||
verbose_name_plural = "Staffs"
|
||||
|
||||
|
||||
class Batch(models.Model):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=255)
|
||||
start_date = models.DateField(null=True, blank=True)
|
||||
end_date = models.DateField(null=True, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Batch"
|
||||
verbose_name_plural = "Batches"
|
||||
|
||||
|
||||
class Routine(models.Model):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=255, null=True, blank=True)
|
||||
start_time = models.TimeField(null=True, blank=True)
|
||||
end_time = models.TimeField(null=True, blank=True)
|
||||
teacher = models.ForeignKey(
|
||||
Staff, related_name="routines", on_delete=models.CASCADE, null=True, blank=True
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Routine"
|
||||
verbose_name_plural = "Routines"
|
||||
|
||||
|
||||
class StudentRoutine(models.Model):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
student = models.ForeignKey(
|
||||
Student, related_name="routines", on_delete=models.CASCADE, null=True
|
||||
)
|
||||
routine = models.ForeignKey(
|
||||
Routine, related_name="students", on_delete=models.CASCADE, null=True
|
||||
)
|
||||
course = models.ForeignKey(Course, on_delete=models.CASCADE, null=True, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.student.name
|
||||
|
||||
|
||||
class Attendance(models.Model):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
date = models.DateField()
|
||||
routine = models.ForeignKey(
|
||||
Routine,
|
||||
related_name="attendances",
|
||||
on_delete=models.CASCADE,
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
teacher = models.ForeignKey(
|
||||
Staff,
|
||||
related_name="attendances",
|
||||
on_delete=models.CASCADE,
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
teacher_attend = models.BooleanField(default=True)
|
||||
class_status = models.BooleanField(default=True)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.date)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Attendance"
|
||||
verbose_name_plural = "Attendances"
|
||||
|
||||
|
||||
class AttendanceRecord(models.Model):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
attendance = models.ForeignKey(
|
||||
Attendance,
|
||||
on_delete=models.CASCADE,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="records",
|
||||
)
|
||||
student = models.ForeignKey(
|
||||
Student,
|
||||
on_delete=models.CASCADE,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="attendance_records",
|
||||
)
|
||||
student_attend = models.BooleanField(default=False)
|
||||
|
||||
# def __str__(self):
|
||||
# return self.student.name
|
||||
|
||||
|
||||
class FCMDevice(models.Model):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
token = models.TextField(unique=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.token
|
||||
|
||||
|
||||
class Notice(models.Model):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
title = models.CharField(max_length=255)
|
||||
image = models.ImageField(upload_to="notice", blank=True, null=True)
|
||||
message = models.TextField(blank=True, null=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
send_push_notification(
|
||||
self.title, self.message, FCMDevice.objects.values_list("token", flat=True)
|
||||
)
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Notice"
|
||||
verbose_name_plural = "Notices"
|
||||
|
||||
|
||||
class Staff_leave(models.Model):
|
||||
LEAVE_STATUS_CHOICES = (
|
||||
(0, 'Pending'),
|
||||
(1, 'Approved'),
|
||||
(2, 'Rejected'),
|
||||
)
|
||||
|
||||
staff = models.ForeignKey(Staff, on_delete=models.CASCADE)
|
||||
date = models.DateField()
|
||||
message = models.TextField()
|
||||
status = models.IntegerField(choices=LEAVE_STATUS_CHOICES, default=0)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.course.name}, Duration: {self.duration})"
|
||||
return f"{self.staff.name} - {self.date}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Staff Leave"
|
||||
verbose_name_plural = "Staff Leaves"
|
||||
ordering = ['-created_at']
|
||||
|
||||
|
||||
class Student_Leave(models.Model):
|
||||
LEAVE_STATUS_CHOICES = (
|
||||
(0, 'Pending'),
|
||||
(1, 'Approved'),
|
||||
(2, 'Rejected'),
|
||||
)
|
||||
|
||||
student = models.ForeignKey(Student, on_delete=models.CASCADE)
|
||||
date = models.DateField()
|
||||
message = models.TextField()
|
||||
status = models.IntegerField(choices=LEAVE_STATUS_CHOICES, default=0)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.student.name} - {self.date}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Student Leave"
|
||||
verbose_name_plural = "Student Leaves"
|
||||
ordering = ['-created_at']
|
||||
|
||||
|
||||
class StudentFeedback(models.Model):
|
||||
student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='feedbacks')
|
||||
subject = models.ForeignKey(Subject, on_delete=models.CASCADE, related_name='feedbacks')
|
||||
teacher = models.ForeignKey(Staff, on_delete=models.CASCADE, related_name='feedbacks')
|
||||
rating = models.IntegerField(choices=[(i, i) for i in range(1, 6)]) # 1-5 rating
|
||||
feedback_text = models.TextField()
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.student.name} - {self.subject.name} - {self.teacher.name}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Student Feedback"
|
||||
verbose_name_plural = "Student Feedbacks"
|
||||
ordering = ['-created_at']
|
||||
unique_together = ['student', 'subject', 'teacher'] # Prevent duplicate feedbacks
|
||||
|
||||
|
||||
class CourseTracking(models.Model):
|
||||
PROGRESS_STATUS_CHOICES = (
|
||||
('Not Started', 'Not Started'),
|
||||
('In Progress', 'In Progress'),
|
||||
('Completed', 'Completed'),
|
||||
('Dropped', 'Dropped'),
|
||||
)
|
||||
|
||||
student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='course_trackings')
|
||||
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='student_trackings')
|
||||
enrollment_date = models.DateField(auto_now_add=True)
|
||||
start_date = models.DateField(null=True, blank=True)
|
||||
expected_end_date = models.DateField(null=True, blank=True)
|
||||
actual_end_date = models.DateField(null=True, blank=True)
|
||||
progress_status = models.CharField(max_length=20, choices=PROGRESS_STATUS_CHOICES, default='Not Started')
|
||||
completion_percentage = models.IntegerField(default=0, help_text="Percentage of course completion (0-100)")
|
||||
notes = models.TextField(blank=True, null=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Course Tracking"
|
||||
verbose_name_plural = "Course Trackings"
|
||||
unique_together = ['student', 'course'] # Ensure one tracking per student per course
|
||||
ordering = ['-created_at']
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.student.name} - {self.course.name}"
|
||||
|
||||
def clean(self):
|
||||
if (
|
||||
self.course.course_type == Course.SEMESTER
|
||||
and self.duration > self.course.duration
|
||||
):
|
||||
raise ValidationError(
|
||||
f"Duration (semester) must not exceed the course's total semesters ({self.course.duration})."
|
||||
)
|
||||
if (
|
||||
self.course.course_type == Course.YEAR
|
||||
and self.duration > self.course.duration
|
||||
):
|
||||
raise ValidationError(
|
||||
f"Duration (year) must not exceed the course's total years ({self.course.duration})."
|
||||
)
|
||||
from django.core.exceptions import ValidationError
|
||||
if self.start_date and self.expected_end_date and self.start_date > self.expected_end_date:
|
||||
raise ValidationError("Start date cannot be after expected end date")
|
||||
if self.actual_end_date and self.start_date and self.actual_end_date < self.start_date:
|
||||
raise ValidationError("Actual end date cannot be before start date")
|
||||
|
||||
def calculate_completion_percentage(self):
|
||||
if not self.start_date or not self.expected_end_date:
|
||||
return 0
|
||||
|
||||
today = date.today()
|
||||
|
||||
# If course is completed, return 100%
|
||||
if self.progress_status == 'Completed':
|
||||
return 100
|
||||
elif self.progress_status == 'Dropped':
|
||||
return 0
|
||||
|
||||
# Calculate total duration in days
|
||||
total_duration = (self.expected_end_date - self.start_date).days
|
||||
if total_duration <= 0:
|
||||
return 0
|
||||
|
||||
# Calculate elapsed time in days
|
||||
elapsed_days = (today - self.start_date).days
|
||||
if elapsed_days <= 0:
|
||||
return 0
|
||||
|
||||
# Calculate percentage based on course duration type
|
||||
if self.course.duration_type == 'Semester':
|
||||
# For semester-based courses (6 months)
|
||||
max_days = 180 # 6 months = 180 days
|
||||
if elapsed_days >= max_days:
|
||||
return 100
|
||||
else: # Yearly based
|
||||
max_days = 365 # 1 year = 365 days
|
||||
if elapsed_days >= max_days:
|
||||
return 100
|
||||
|
||||
# Calculate percentage based on elapsed time vs total duration
|
||||
percentage = min(100, int((elapsed_days / total_duration) * 100))
|
||||
return percentage
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# Validate dates
|
||||
self.clean()
|
||||
|
||||
# Calculate completion percentage
|
||||
self.completion_percentage = self.calculate_completion_percentage()
|
||||
|
||||
# Update progress status based on completion percentage
|
||||
if self.completion_percentage >= 100:
|
||||
self.progress_status = 'Completed'
|
||||
if not self.actual_end_date:
|
||||
self.actual_end_date = date.today()
|
||||
elif self.completion_percentage > 0:
|
||||
self.progress_status = 'In Progress'
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def is_completed(self):
|
||||
return self.progress_status == 'Completed'
|
||||
|
||||
@property
|
||||
def is_active(self):
|
||||
return self.progress_status == 'In Progress'
|
||||
|
||||
@property
|
||||
def remaining_days(self):
|
||||
if not self.expected_end_date:
|
||||
return None
|
||||
today = date.today()
|
||||
remaining = (self.expected_end_date - today).days
|
||||
return max(0, remaining)
|
||||
|
||||
@property
|
||||
def duration_type(self):
|
||||
return self.course.duration_type
|
||||
|
||||
@property
|
||||
def total_duration_days(self):
|
||||
if not self.start_date or not self.expected_end_date:
|
||||
return None
|
||||
return (self.expected_end_date - self.start_date).days
|
||||
|
||||
def get_completion_percentage(self):
|
||||
"""
|
||||
Get completion percentage with caching
|
||||
"""
|
||||
return get_cached_percentage(self.id)
|
||||
|
||||
def force_update_percentage(self):
|
||||
"""
|
||||
Force update the completion percentage and clear cache
|
||||
"""
|
||||
cache_key = f'course_tracking_percentage_{self.id}'
|
||||
cache.delete(cache_key)
|
||||
self.save() # This will recalculate and update the percentage
|
||||
|
||||
|
||||
class Attendance(models.Model): # Subject Attendance
|
||||
id = models.AutoField(primary_key=True)
|
||||
subject_id = models.ForeignKey(Subject, on_delete=models.DO_NOTHING)
|
||||
attendance_date = models.DateField()
|
||||
academic_year_id = models.ForeignKey(AcademicYear, on_delete=models.CASCADE)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
def get_cached_percentage(tracking_id):
|
||||
"""
|
||||
Get cached completion percentage for a course tracking
|
||||
"""
|
||||
cache_key = f'course_tracking_percentage_{tracking_id}'
|
||||
percentage = cache.get(cache_key)
|
||||
if percentage is None:
|
||||
try:
|
||||
tracking = CourseTracking.objects.get(id=tracking_id)
|
||||
percentage = tracking.completion_percentage
|
||||
cache.set(cache_key, percentage, 3600)
|
||||
except CourseTracking.DoesNotExist:
|
||||
return 0
|
||||
return percentage
|
||||
|
||||
|
||||
class AttendanceReport(models.Model): # Individual Student Attendance
|
||||
id = models.AutoField(primary_key=True)
|
||||
student_id = models.ForeignKey(Student, on_delete=models.DO_NOTHING)
|
||||
attendance_id = models.ForeignKey(Attendance, on_delete=models.CASCADE)
|
||||
status = models.BooleanField(default=False)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now_add=True)
|
||||
@receiver(post_save, sender=CourseTracking)
|
||||
def update_completion_percentage(sender, instance, **kwargs):
|
||||
"""
|
||||
Signal to update completion percentage after save
|
||||
Also caches the percentage for 1 hour to avoid frequent recalculations
|
||||
"""
|
||||
cache_key = f'course_tracking_percentage_{instance.id}'
|
||||
cache.set(cache_key, instance.completion_percentage, 3600) # Cache for 1 hour
|
||||
|
||||
|
||||
class LeaveReportStudent(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
student_id = models.ForeignKey(Student, on_delete=models.CASCADE)
|
||||
leave_date = models.DateField()
|
||||
leave_message = models.TextField()
|
||||
leave_status = models.IntegerField(default=0)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
|
||||
class LeaveReportTeacher(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
teacher_id = models.ForeignKey(Teacher, on_delete=models.CASCADE)
|
||||
leave_date = models.DateField()
|
||||
leave_message = models.TextField()
|
||||
leave_status = models.IntegerField(default=0)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
|
||||
class FeedbackStudent(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
student_id = models.ForeignKey(Student, on_delete=models.CASCADE)
|
||||
feedback = models.TextField()
|
||||
feedback_reply = models.TextField(blank=True, null=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
|
||||
class FeedbackTeacher(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
teacher_id = models.ForeignKey(Teacher, on_delete=models.CASCADE)
|
||||
feedback = models.TextField()
|
||||
feedback_reply = models.TextField(blank=True, null=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
@@ -1,163 +0,0 @@
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
from django.shortcuts import render
|
||||
|
||||
|
||||
@login_required
|
||||
def student_dashboard(request):
|
||||
return render(request, "student/dashboard.html") # Student-specific page
|
||||
|
||||
|
||||
# @login_required
|
||||
# @student_required
|
||||
# def student_view_attendance(request):
|
||||
# student = Student.objects.get(admin=request.user.id)
|
||||
# course = student.course_id
|
||||
# subjects = Subject.objects.filter(course_id=course)
|
||||
# student = Student.objects.get(admin=user)
|
||||
# student_notifcation = Student.objects.get(admin=request.user.id)
|
||||
# notifications = NotificationStudent.objects.filter(
|
||||
# student_id=student_notifcation.id
|
||||
# )
|
||||
# return render(
|
||||
# request,
|
||||
# "student_template/student_view_attendance.html",
|
||||
# {"subjects": subjects, "student": student, "notifications": notifications},
|
||||
# )
|
||||
#
|
||||
#
|
||||
# @login_required
|
||||
# @student_required
|
||||
# def student_view_attendance_post(request):
|
||||
# subject_id = request.POST.get("subject")
|
||||
# start_date = request.POST.get("start_date")
|
||||
# end_date = request.POST.get("end_date")
|
||||
#
|
||||
# start_data_parse = datetime.datetime.strptime(start_date, "%Y-%m-%d").date()
|
||||
# end_data_parse = datetime.datetime.strptime(end_date, "%Y-%m-%d").date()
|
||||
# subject_obj = Subjects.objects.get(id=subject_id)
|
||||
# user_object = CustomUser.objects.get(id=request.user.id)
|
||||
# stud_obj = Students.objects.get(admin=user_object)
|
||||
# user = CustomUser.objects.get(id=request.user.id)
|
||||
# student = Students.objects.get(admin=user)
|
||||
# student_notifcation = Students.objects.get(admin=request.user.id)
|
||||
# notifications = NotificationStudent.objects.filter(
|
||||
# student_id=student_notifcation.id
|
||||
# )
|
||||
#
|
||||
# attendance = Attendance.objects.filter(
|
||||
# attendance_date__range=(start_data_parse, end_data_parse),
|
||||
# subject_id=subject_obj,
|
||||
# )
|
||||
# attendance_reports = AttendanceReport.objects.filter(
|
||||
# attendance_id__in=attendance, student_id=stud_obj
|
||||
# )
|
||||
# return render(
|
||||
# request,
|
||||
# "student_template/student_attendance_data.html",
|
||||
# {
|
||||
# "attendance_reports": attendance_reports,
|
||||
# "student": student,
|
||||
# "notifications": notifications,
|
||||
# },
|
||||
# )
|
||||
#
|
||||
#
|
||||
# @login_required
|
||||
# @student_required
|
||||
# def student_apply_leave(request):
|
||||
# student_obj = Student.objects.get(admin=request.user.id)
|
||||
# leave_data = LeaveReportStudent.objects.filter(student_id=student_obj)
|
||||
# user = CustomUser.objects.get(id=request.user.id)
|
||||
# student = Student.objects.get(admin=user)
|
||||
# student_notifcation = Student.objects.get(admin=request.user.id)
|
||||
# notifications = NotificationStudent.objects.filter(
|
||||
# student_id=student_notifcation.id
|
||||
# )
|
||||
# return render(
|
||||
# request,
|
||||
# "student/apply_leave.html",
|
||||
# {"leave_data": leave_data, "student": student, "notifications": notifications},
|
||||
# )
|
||||
#
|
||||
#
|
||||
# @login_required
|
||||
# @student_required
|
||||
# def student_apply_leave_save(request):
|
||||
# if request.method != "POST":
|
||||
# return HttpResponseRedirect(reverse("student_apply_leave"))
|
||||
# else:
|
||||
# leave_start_date = request.POST.get("leave_start_date")
|
||||
# leave_end_date = request.POST.get("leave_end_date")
|
||||
# leave_date = request.POST.get("leave_date")
|
||||
# leave_msg = request.POST.get("leave_msg")
|
||||
#
|
||||
# student_obj = Student.objects.get(admin=request.user.id)
|
||||
# try:
|
||||
# leave_report = LeaveReportStudent(
|
||||
# student_id=student_obj,
|
||||
# leave_start_date=leave_start_date,
|
||||
# leave_end_date=leave_end_date,
|
||||
# leave_message=leave_msg,
|
||||
# leave_status=0,
|
||||
# )
|
||||
# leave_report.save()
|
||||
# messages.success(request, "Successfully Applied for Leave")
|
||||
# return HttpResponseRedirect(reverse("student_apply_leave"))
|
||||
# except:
|
||||
# messages.error(request, "Failed To Apply for Leave")
|
||||
# return HttpResponseRedirect(reverse("student_apply_leave"))
|
||||
#
|
||||
#
|
||||
# @login_required
|
||||
# @student_required
|
||||
# def student_feedback(request):
|
||||
# staff_id = Student.objects.get(admin=request.user.id)
|
||||
# feedback_data = FeedBackStudent.objects.filter(student_id=staff_id)
|
||||
# student = Student.objects.get(admin=user)
|
||||
# student_notifcation = Student.objects.get(admin=request.user.id)
|
||||
# notifications = NotificationStudent.objects.filter(
|
||||
# student_id=student_notifcation.id
|
||||
# )
|
||||
# return render(
|
||||
# request,
|
||||
# "student_template/student_feedback.html",
|
||||
# {
|
||||
# "feedback_data": feedback_data,
|
||||
# "student": student,
|
||||
# "notifications": notifications,
|
||||
# },
|
||||
# )
|
||||
#
|
||||
#
|
||||
# @login_required
|
||||
# @student_required
|
||||
# def student_feedback_save(request):
|
||||
# if request.method != "POST":
|
||||
# return HttpResponseRedirect(reverse("student_feedback"))
|
||||
# else:
|
||||
# feedback_msg = request.POST.get("feedback_msg")
|
||||
#
|
||||
# student_obj = Student.objects.get(admin=request.user.id)
|
||||
# try:
|
||||
# feedback = FeedBackStudent(
|
||||
# student_id=student_obj, feedback=feedback_msg, feedback_reply=""
|
||||
# )
|
||||
# feedback.save()
|
||||
# messages.success(request, "Feedback submitted for review")
|
||||
# return HttpResponseRedirect(reverse("student_feedback"))
|
||||
# except:
|
||||
# messages.error(request, "Could not Submit")
|
||||
# return HttpResponseRedirect(reverse("student_feedback"))
|
||||
#
|
||||
#
|
||||
# @csrf_exempt
|
||||
# def student_fcmtoken_save(request):
|
||||
# token = request.POST.get("token")
|
||||
# try:
|
||||
# student = Student.objects.get(admin=request.user.id)
|
||||
# student.fcm_token = token
|
||||
# student.save()
|
||||
# return HttpResponse("True")
|
||||
# except:
|
||||
# return HttpResponse("False")
|
||||
@@ -1,7 +0,0 @@
|
||||
from django.shortcuts import render
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
|
||||
@login_required
|
||||
def teacher_dashboard(request):
|
||||
return render(request, "teacher/dashboard.html")
|
||||
-121
@@ -1,121 +0,0 @@
|
||||
from django.urls import path
|
||||
from app import adminViews, studentViews, teacherViews
|
||||
|
||||
urlpatterns = [
|
||||
path("dashboard/", adminViews.admin_home, name="dashboard"),
|
||||
path("add_course/", adminViews.add_course, name="add_course"),
|
||||
path("manage_course", adminViews.manage_course, name="manage_course"),
|
||||
path("delete_course/<course_id>/", adminViews.delete_course, name="delete_course"),
|
||||
path("edit_course/<int:course_id>/", adminViews.edit_course, name="edit_course"),
|
||||
path("add_academicyear/", adminViews.add_academicyear, name="add_academicyear"),
|
||||
path(
|
||||
"manage_academicyear/",
|
||||
adminViews.manage_academicyear,
|
||||
name="manage_academicyear",
|
||||
),
|
||||
path(
|
||||
"delete_academicyear/<academic_year_id>/",
|
||||
adminViews.delete_academicyear,
|
||||
name="delete_academicyear",
|
||||
),
|
||||
path(
|
||||
"edit_academicyears/<int:pk>/",
|
||||
adminViews.edit_academicyear,
|
||||
name="edit_academicyear",
|
||||
),
|
||||
path("manage_subject/", adminViews.manage_subjects, name="manage_subject"),
|
||||
path("add_subject/", adminViews.add_subject, name="add_subject"),
|
||||
path("edit_subject/<int:pk>/", adminViews.edit_subject, name="edit_subject"),
|
||||
path(
|
||||
"delete_subject/<subject_id>/", adminViews.delete_subject, name="delete_subject"
|
||||
),
|
||||
path("manage_student/", adminViews.manage_student, name="manage_student"),
|
||||
path("add_student/", adminViews.add_student, name="add_student"),
|
||||
path(
|
||||
"edit_student/<int:student_id>/", adminViews.edit_student, name="edit_student"
|
||||
),
|
||||
path(
|
||||
"delete_student/<int:student_id>/",
|
||||
adminViews.delete_student,
|
||||
name="delete_student",
|
||||
),
|
||||
path("manage_teacher/", adminViews.manage_teacher, name="manage_teacher"),
|
||||
path("add_teacher/", adminViews.add_teacher, name="add_teacher"),
|
||||
path(
|
||||
"edit_teacher/<int:teacher_id>/", adminViews.edit_teacher, name="edit_teacher"
|
||||
),
|
||||
path(
|
||||
"delete_teacher/<int:teacher_id>/",
|
||||
adminViews.delete_teacher,
|
||||
name="delete_teacher",
|
||||
),
|
||||
path(
|
||||
"student_feedback_message/",
|
||||
adminViews.student_feedback_message,
|
||||
name="student_feedback_message",
|
||||
),
|
||||
path(
|
||||
"student_feedback_message_reply/",
|
||||
adminViews.student_feedback_message_reply,
|
||||
name="student_feedback_message_reply",
|
||||
),
|
||||
path(
|
||||
"teacher_feedback/",
|
||||
adminViews.teacher_feedback,
|
||||
name="teacher_feedback",
|
||||
),
|
||||
path(
|
||||
"teacher_feedback_replied/",
|
||||
adminViews.teacher_feedback_replied,
|
||||
name="teacher_feedback_replied",
|
||||
),
|
||||
path(
|
||||
"student_leave_view/", adminViews.student_leave_view, name="student_leave_view"
|
||||
),
|
||||
path(
|
||||
"student_leave_approve/<leave_id>/",
|
||||
adminViews.student_leave_approve,
|
||||
name="student_leave_approve",
|
||||
),
|
||||
path(
|
||||
"student_leave_reject/<leave_id>/",
|
||||
adminViews.student_leave_reject,
|
||||
name="student_leave_reject",
|
||||
),
|
||||
path(
|
||||
"teacher_leave_view/", adminViews.teacher_leave_view, name="teacher_leave_view"
|
||||
),
|
||||
path(
|
||||
"teacher_leave_approve/<leave_id>/",
|
||||
adminViews.teacher_leave_approve,
|
||||
name="teacher_leave_approve",
|
||||
),
|
||||
path(
|
||||
"teacher_leave_reject/<leave_id>/",
|
||||
adminViews.teacher_leave_reject,
|
||||
name="teacher_leave_reject",
|
||||
),
|
||||
path(
|
||||
"admin_view_attendance/",
|
||||
adminViews.admin_view_attendance,
|
||||
name="admin_view_attendance",
|
||||
),
|
||||
path(
|
||||
"admin_get_attendance_dates/",
|
||||
adminViews.admin_get_attendance_dates,
|
||||
name="admin_get_attendance_dates",
|
||||
),
|
||||
path(
|
||||
"admin_get_attendance_student/",
|
||||
adminViews.admin_get_attendance_student,
|
||||
name="admin_get_attendance_student",
|
||||
),
|
||||
# ── Student ───────────────────────────────────────────────────────────
|
||||
path(
|
||||
"student_dashboard/", studentViews.student_dashboard, name="student_dashboard"
|
||||
),
|
||||
# ── teacher ───────────────────────────────────────────────────────────
|
||||
path(
|
||||
"teacher_dashboard/", teacherViews.teacher_dashboard, name="teacher_dashboard"
|
||||
),
|
||||
]
|
||||
+43
-5
@@ -1,6 +1,44 @@
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
from django.shortcuts import render, redirect
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from app.models import FCMDevice
|
||||
from django.shortcuts import render
|
||||
from django.http import JsonResponse, HttpResponse
|
||||
# Create your views here.
|
||||
|
||||
|
||||
# FireBase
|
||||
def saveFCMToken(request, token):
|
||||
try:
|
||||
FCMDevice(token=token).save()
|
||||
except:
|
||||
pass
|
||||
return JsonResponse({})
|
||||
|
||||
|
||||
def showFirebaseJS(request):
|
||||
data = """
|
||||
importScripts('https://www.gstatic.com/firebasejs/11.0.2/firebase-app-compat.js');
|
||||
importScripts('https://www.gstatic.com/firebasejs/11.0.2/firebase-messaging-compat.js');
|
||||
|
||||
firebase.initializeApp({
|
||||
apiKey: "AIzaSyAVzOJh5v8_oZg4MoQkq0CzrAbeyHGn4z4",
|
||||
authDomain: "institute-management-sys-a2d20.firebaseapp.com",
|
||||
projectId: "institute-management-sys-a2d20",
|
||||
storageBucket: "institute-management-sys-a2d20.firebasestorage.app",
|
||||
messagingSenderId: "777235542100",
|
||||
appId: "1:777235542100:web:4d0cb9553918cb3cc23dc1",
|
||||
measurementId: "G-4QP9GYV0SJ"
|
||||
});
|
||||
|
||||
const messaging = firebase.messaging();
|
||||
|
||||
messaging.onBackgroundMessage((payload) => {
|
||||
|
||||
const notificationTitle = payload.notification.title;
|
||||
const notificationOptions = {
|
||||
body: payload.notification.body,
|
||||
icon: payload.notification.icon
|
||||
};
|
||||
|
||||
return self.registration.showNotification(notificationTitle, notificationOptions);
|
||||
});
|
||||
"""
|
||||
return HttpResponse(data, content_type="text/javascript")
|
||||
Reference in new issue
Block a user