College Management System using Django - Python Project - GeeksforGeeks

College Management System using Django - Python Project

Last Updated : 13 Nov, 2026

A College Management System is a web application that simplifies academic administration by managing student records, staff information, courses, attendance, leave applications, and examination results. This project uses Django and SQLite to provide separate dashboards for the Head of Department (HOD), staff, and students.

Key Features

Application provides three role-based dashboards with different permissions and functionalities.

1. Head of Department (HOD)

  • Manages student and staff accounts.
  • Creates courses and subjects and assigns faculty members.
  • Monitors attendance and examination results.
  • Approves or rejects leave applications.
  • Reviews feedback and responds to students and staff.

2. Staff

  • Views assigned subjects and enrolled students.
  • Records and manages student attendance.
  • Adds examination results and marks.
  • Submits leave applications.
  • Sends feedback to the HOD.

3. Student

  • Views personal and academic information.
  • Checks attendance records and attendance percentage.
  • Views examination results.
  • Submits leave applications and tracks their status.
  • Sends feedback to the administration.

Project Structure

Follow the steps below to create and run the application.

1. Creating a Virtual Environment

Create a project directory and virtual environment to isolate dependencies.

mkdir College_Management_System
cd College_Management_System
python3 -m venv .venv
source .venv/bin/activate

For Windows:

py -m venv .venv
.venv\Scripts\activate

2. Installing Django

Create a requirement.txt file in the project root directory.

Django==6.1.2

Install Django using the following command:

python -m pip install -r requirements.txt

3. Creating a Django Project and Application

Create the main Django project and an application named management.

django-admin startproject college_portal .
python manage.py startapp management

Explanation:

  • startproject creates the main project configuration.
  • startapp creates the application responsible for college management functionality.
  • manage.py provides commands for managing the Django project.

4. Configuring Django Application

Open college_portal/settings.py and add management to INSTALLED_APPS.

Python
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'management',
]

Configure the template directory by updating the TEMPLATES setting:

Python
'DIRS': [BASE_DIR / 'templates'],

Add following configuration at the bottom of settings.py:

Python
AUTH_USER_MODEL = 'management.CollegeUser'

TIME_ZONE = 'Asia/Kolkata'

STATIC_URL = 'static/'

LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'dashboard'
LOGOUT_REDIRECT_URL = 'login'

Explanation:

  • INSTALLED_APPS registers the college management application.
  • DIRS allows Django to locate project-level HTML templates.
  • AUTH_USER_MODEL specifies the custom authentication model.
  • LOGIN_REDIRECT_URL specifies the page displayed after successful login.

5. Creating Database Models

Create models.py inside the management application. These models store user information, academic records, attendance, examination results, leave requests, and feedback.

Add following code:

Python
from django.db import models
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.core.validators import MinValueValidator


class CollegeUser(AbstractUser):

    class Role(models.TextChoices):
        HOD = "HOD", "Head of Department"
        STAFF = "STAFF", "Staff"
        STUDENT = "STUDENT", "Student"

    role = models.CharField(
        max_length=10,
        choices=Role.choices,
        default=Role.STUDENT
    )

    def __str__(self):
        return self.username


class Course(models.Model):

    name = models.CharField(max_length=120, unique=True)
    code = models.CharField(max_length=20, unique=True)

    def __str__(self):
        return f"{self.name} ({self.code})"


class StaffProfile(models.Model):

    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="staff_profile"
    )

    department = models.CharField(max_length=120)

    def __str__(self):
        return self.user.username


class StudentProfile(models.Model):

    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="student_profile"
    )

    roll_number = models.CharField(max_length=30, unique=True)

    course = models.ForeignKey(
        Course,
        on_delete=models.PROTECT,
        related_name="students"
    )

    admission_year = models.PositiveSmallIntegerField()

    def __str__(self):
        return self.roll_number


class Subject(models.Model):

    name = models.CharField(max_length=120)
    code = models.CharField(max_length=20, unique=True)

    course = models.ForeignKey(
        Course,
        on_delete=models.CASCADE,
        related_name="subjects"
    )

    staff = models.ForeignKey(
        StaffProfile,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="subjects"
    )

    def __str__(self):
        return self.name


class Attendance(models.Model):

    subject = models.ForeignKey(
        Subject,
        on_delete=models.CASCADE,
        related_name="attendance_records"
    )

    student = models.ForeignKey(
        StudentProfile,
        on_delete=models.CASCADE,
        related_name="attendance_records"
    )

    date = models.DateField()

    present = models.BooleanField(default=False)

    recorded_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT
    )

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["subject", "student", "date"],
                name="unique_student_subject_attendance_per_day"
            )
        ]

    def __str__(self):
        return f"{self.student} - {self.subject} - {self.date}"


class LeaveApplication(models.Model):

    class Status(models.TextChoices):
        PENDING = "PENDING", "Pending"
        APPROVED = "APPROVED", "Approved"
        REJECTED = "REJECTED", "Rejected"

    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="leave_applications"
    )

    start_date = models.DateField()
    end_date = models.DateField()
    reason = models.TextField()

    status = models.CharField(
        max_length=10,
        choices=Status.choices,
        default=Status.PENDING
    )

    reviewed_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="reviewed_leave_applications"
    )

    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.user.username}: {self.start_date}"


class Result(models.Model):

    student = models.ForeignKey(
        StudentProfile,
        on_delete=models.CASCADE,
        related_name="results"
    )

    subject = models.ForeignKey(
        Subject,
        on_delete=models.CASCADE,
        related_name="results"
    )

    examination = models.CharField(max_length=120)

    marks_obtained = models.DecimalField(
        max_digits=6,
        decimal_places=2,
        validators=[MinValueValidator(0)]
    )

    maximum_marks = models.DecimalField(
        max_digits=6,
        decimal_places=2,
        validators=[MinValueValidator(0)]
    )

    added_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT
    )

    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.student} - {self.examination}"


class Feedback(models.Model):

    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="feedback_messages"
    )

    message = models.TextField()

    response = models.TextField(blank=True)

    responded_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="feedback_responses"
    )

    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"Feedback from {self.user.username}"

Explanation:

  • CollegeUser extends AbstractUser to introduce HOD, staff, and student roles.
  • Course and Subject store academic information.
  • StudentProfile and StaffProfile maintain additional user details.
  • Attendance stores daily attendance records.
  • LeaveApplication maintains leave requests and approval status.
  • Result stores examination marks.
  • Feedback stores messages and administrative responses.

6. Creating Django Forms

Create forms.py inside the management directory. These forms handle student and staff registration, course creation, subject assignment, examination results, leave applications, and feedback.

Python
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.password_validation import validate_password

from .models import (
    Course, Subject, StaffProfile, StudentProfile,
    Result, LeaveApplication, Feedback
)

User = get_user_model()


class StudentCreateForm(forms.Form):

    username = forms.CharField(max_length=150)
    first_name = forms.CharField(max_length=150)
    last_name = forms.CharField(max_length=150, required=False)
    email = forms.EmailField()
    password = forms.CharField(widget=forms.PasswordInput)

    roll_number = forms.CharField(max_length=30)
    course = forms.ModelChoiceField(queryset=Course.objects.all())
    admission_year = forms.IntegerField(min_value=2000, max_value=2100)

    def clean_username(self):
        value = self.cleaned_data["username"]

        if User.objects.filter(username=value).exists():
            raise forms.ValidationError("Username already exists.")

        return value

    def clean_password(self):
        value = self.cleaned_data["password"]
        validate_password(value)
        return value

    def clean_roll_number(self):
        value = self.cleaned_data["roll_number"]

        if StudentProfile.objects.filter(roll_number=value).exists():
            raise forms.ValidationError("Roll number already exists.")

        return value


class StaffCreateForm(forms.Form):

    username = forms.CharField(max_length=150)
    first_name = forms.CharField(max_length=150)
    last_name = forms.CharField(max_length=150, required=False)
    email = forms.EmailField()
    password = forms.CharField(widget=forms.PasswordInput)
    department = forms.CharField(max_length=120)

    def clean_username(self):
        value = self.cleaned_data["username"]

        if User.objects.filter(username=value).exists():
            raise forms.ValidationError("Username already exists.")

        return value

    def clean_password(self):
        value = self.cleaned_data["password"]
        validate_password(value)
        return value


class CourseForm(forms.ModelForm):

    class Meta:
        model = Course
        fields = ["name", "code"]


class SubjectForm(forms.ModelForm):

    class Meta:
        model = Subject
        fields = ["name", "code", "course", "staff"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields["staff"].queryset = (
            StaffProfile.objects.select_related("user").all()
        )

        self.fields["staff"].required = False


class ResultForm(forms.ModelForm):

    class Meta:
        model = Result
        fields = [
            "student", "subject", "examination",
            "marks_obtained", "maximum_marks"
        ]

        widgets = {
            "marks_obtained": forms.NumberInput(
                attrs={"step": "0.01", "min": "0"}
            ),
            "maximum_marks": forms.NumberInput(
                attrs={"step": "0.01", "min": "0.01"}
            ),
        }

    def __init__(self, *args, staff_profile=None, **kwargs):
        super().__init__(*args, **kwargs)

        subjects = Subject.objects.all()

        if staff_profile is not None:
            subjects = subjects.filter(staff=staff_profile)

        self.fields["subject"].queryset = subjects.select_related("course")

        course_ids = subjects.values_list("course_id", flat=True)

        self.fields["student"].queryset = StudentProfile.objects.filter(
            course_id__in=course_ids
        ).select_related("user")

    def clean(self):
        cleaned = super().clean()

        student = cleaned.get("student")
        subject = cleaned.get("subject")
        obtained = cleaned.get("marks_obtained")
        maximum = cleaned.get("maximum_marks")

        if student and subject and student.course_id != subject.course_id:
            self.add_error(
                "student",
                "Student does not belong to the selected subject's course."
            )

        if maximum is not None and maximum <= 0:
            self.add_error("maximum_marks", "Maximum marks must be positive.")

        if obtained is not None and maximum is not None and obtained > maximum:
            self.add_error(
                "marks_obtained",
                "Marks cannot exceed maximum marks."
            )

        return cleaned


class LeaveApplicationForm(forms.ModelForm):

    class Meta:
        model = LeaveApplication

        fields = ["start_date", "end_date", "reason"]

        widgets = {
            "start_date": forms.DateInput(attrs={"type": "date"}),
            "end_date": forms.DateInput(attrs={"type": "date"}),
        }

    def clean(self):
        cleaned = super().clean()

        start = cleaned.get("start_date")
        end = cleaned.get("end_date")

        if start and end and end < start:
            self.add_error("end_date", "Invalid leave date range.")

        return cleaned


class FeedbackForm(forms.ModelForm):

    class Meta:
        model = Feedback
        fields = ["message"]


class FeedbackReplyForm(forms.ModelForm):

    class Meta:
        model = Feedback
        fields = ["response"]

Explanation:

  • StudentCreateForm and StaffCreateForm validate registration details.
  • CourseForm and SubjectForm handle academic information.
  • ResultForm validates examination marks and assigned subjects.
  • LeaveApplicationForm checks the requested leave dates.
  • FeedbackForm and FeedbackReplyForm manage communication.

7. Implementing Role-Based Access Control

Create decorators.py to restrict access to dashboard operations based on the logged-in user's role.

Python
from functools import wraps

from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied


def role_required(*roles):

    def decorator(view_func):

        @wraps(view_func)
        @login_required
        def wrapper(request, *args, **kwargs):

            if request.user.role not in roles:
                raise PermissionDenied(
                    "You do not have permission to access this page."
                )

            return view_func(request, *args, **kwargs)

        return wrapper

    return decorator

Explanation:

  • login_required ensures that only authenticated users access protected pages.
  • role_required checks whether the user has the required role.
  • PermissionDenied blocks unauthorized access.

8. Implementing Application Views

Create views.py to handle the main application operations. The views connect forms, database models, authentication, and HTML templates.

Add the following code:

Python
from django.contrib import messages
from django.contrib.auth import get_user_model
from django.db import transaction
from django.db.models import Count
from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404, redirect, render
from django.utils.dateparse import parse_date
from django.views.decorators.http import require_POST

from .decorators import role_required

from .forms import (
    StudentCreateForm,
    StaffCreateForm,
    CourseForm,
    SubjectForm,
    ResultForm,
    LeaveApplicationForm,
    FeedbackForm,
    FeedbackReplyForm,
)

from .models import (
    Attendance,
    Course,
    Feedback,
    LeaveApplication,
    Result,
    StaffProfile,
    StudentProfile,
    Subject,
)

User = get_user_model()


def dashboard(request):

    if not request.user.is_authenticated:
        return redirect("login")

    if request.user.role == User.Role.HOD:
        return redirect("hod_dashboard")

    if request.user.role == User.Role.STAFF:
        return redirect("staff_dashboard")

    if request.user.role == User.Role.STUDENT:
        return redirect("student_dashboard")

    return HttpResponseForbidden("No dashboard assigned.")


# ---------------- HOD DASHBOARD ----------------

@role_required(User.Role.HOD)
def hod_dashboard(request):

    context = {
        "student_count": StudentProfile.objects.count(),
        "staff_count": StaffProfile.objects.count(),
        "course_count": Course.objects.count(),
        "subject_count": Subject.objects.count(),

        "pending_leaves": LeaveApplication.objects.filter(
            status=LeaveApplication.Status.PENDING
        ).count(),

        "recent_leaves": LeaveApplication.objects.select_related(
            "user"
        )[:5],
    }

    return render(
        request,
        "management/hod_dashboard.html",
        context
    )


@role_required(User.Role.HOD)
def student_list(request):

    students = StudentProfile.objects.select_related(
        "user", "course"
    )

    rows = [
        (
            student.roll_number,
            student.user.get_full_name(),
            student.user.email,
            student.course.name,
            student.admission_year
        )
        for student in students
    ]

    return render(request, "management/records.html", {
        "title": "Students",
        "headers": [
            "Roll Number", "Name", "Email", "Course", "Admission Year"
        ],
        "rows": rows,
        "add_url": "add_student",
    })


@role_required(User.Role.HOD)
def add_student(request):

    form = StudentCreateForm(request.POST or None)

    if request.method == "POST" and form.is_valid():

        data = form.cleaned_data

        with transaction.atomic():

            user = User.objects.create_user(
                username=data["username"],
                password=data["password"],
                first_name=data["first_name"],
                last_name=data["last_name"],
                email=data["email"],
                role=User.Role.STUDENT,
            )

            StudentProfile.objects.create(
                user=user,
                roll_number=data["roll_number"],
                course=data["course"],
                admission_year=data["admission_year"],
            )

        messages.success(request, "Student created successfully.")

        return redirect("student_list")

    return render(request, "management/form.html", {
        "title": "Add Student",
        "form": form,
    })


@role_required(User.Role.HOD)
def staff_list(request):

    staff = StaffProfile.objects.select_related("user")

    rows = [
        (
            item.user.username,
            item.user.get_full_name(),
            item.user.email,
            item.department,
            item.subjects.count()
        )
        for item in staff
    ]

    return render(request, "management/records.html", {
        "title": "Staff",
        "headers": [
            "Username", "Name", "Email", "Department", "Subjects"
        ],
        "rows": rows,
        "add_url": "add_staff",
    })


@role_required(User.Role.HOD)
def add_staff(request):

    form = StaffCreateForm(request.POST or None)

    if request.method == "POST" and form.is_valid():

        data = form.cleaned_data

        with transaction.atomic():

            user = User.objects.create_user(
                username=data["username"],
                password=data["password"],
                first_name=data["first_name"],
                last_name=data["last_name"],
                email=data["email"],
                role=User.Role.STAFF,
            )

            StaffProfile.objects.create(
                user=user,
                department=data["department"]
            )

        messages.success(request, "Staff member created.")

        return redirect("staff_list")

    return render(request, "management/form.html", {
        "title": "Add Staff",
        "form": form,
    })


@role_required(User.Role.HOD)
def course_list(request):

    courses = Course.objects.annotate(
        student_total=Count("students")
    )

    rows = [
        (
            course.code,
            course.name,
            course.student_total,
            course.subjects.count()
        )
        for course in courses
    ]

    return render(request, "management/records.html", {
        "title": "Courses",
        "headers": ["Code", "Course", "Students", "Subjects"],
        "rows": rows,
        "add_url": "add_course",
    })


@role_required(User.Role.HOD)
def add_course(request):

    form = CourseForm(request.POST or None)

    if request.method == "POST" and form.is_valid():

        form.save()

        messages.success(request, "Course added successfully.")

        return redirect("course_list")

    return render(request, "management/form.html", {
        "title": "Add Course",
        "form": form,
    })


@role_required(User.Role.HOD)
def subject_list(request):

    subjects = Subject.objects.select_related(
        "course", "staff__user"
    )

    rows = [
        (
            item.code,
            item.name,
            item.course.name,
            item.staff.user.get_full_name()
            if item.staff else "Not assigned"
        )
        for item in subjects
    ]

    return render(request, "management/records.html", {
        "title": "Subjects",
        "headers": ["Code", "Subject", "Course", "Assigned Staff"],
        "rows": rows,
        "add_url": "add_subject",
    })


@role_required(User.Role.HOD)
def add_subject(request):

    form = SubjectForm(request.POST or None)

    if request.method == "POST" and form.is_valid():

        form.save()

        messages.success(request, "Subject added successfully.")

        return redirect("subject_list")

    return render(request, "management/form.html", {
        "title": "Add Subject",
        "form": form,
    })


@role_required(User.Role.HOD)
def hod_leave_list(request):

    leaves = LeaveApplication.objects.select_related(
        "user", "reviewed_by"
    )

    return render(request, "management/leave_list.html", {
        "title": "Leave Applications",
        "leaves": leaves,
        "can_review": True,
    })


@role_required(User.Role.HOD)
@require_POST
def review_leave(request, pk):

    leave = get_object_or_404(LeaveApplication, pk=pk)

    action = request.POST.get("action")

    if leave.status != LeaveApplication.Status.PENDING:

        messages.warning(request, "Application already reviewed.")

    elif action == "approve":

        leave.status = LeaveApplication.Status.APPROVED
        leave.reviewed_by = request.user
        leave.save(update_fields=["status", "reviewed_by"])

        messages.success(request, "Leave approved.")

    elif action == "reject":

        leave.status = LeaveApplication.Status.REJECTED
        leave.reviewed_by = request.user
        leave.save(update_fields=["status", "reviewed_by"])

        messages.success(request, "Leave rejected.")

    else:

        messages.error(request, "Invalid action.")

    return redirect("hod_leave_list")


@role_required(User.Role.HOD)
def hod_feedback_list(request):

    feedback = Feedback.objects.select_related(
        "user", "responded_by"
    )

    return render(request, "management/feedback_list.html", {
        "title": "Feedback",
        "feedback_items": feedback,
    })


@role_required(User.Role.HOD)
def reply_feedback(request, pk):

    item = get_object_or_404(Feedback, pk=pk)

    form = FeedbackReplyForm(
        request.POST or None,
        instance=item
    )

    if request.method == "POST" and form.is_valid():

        saved = form.save(commit=False)
        saved.responded_by = request.user
        saved.save()

        messages.success(request, "Feedback response saved.")

        return redirect("hod_feedback_list")

    return render(request, "management/form.html", {
        "title": "Respond to Feedback",
        "form": form,
    })


@role_required(User.Role.HOD)
def hod_attendance_list(request):

    records = Attendance.objects.select_related(
        "student__user",
        "student__course",
        "subject"
    )

    rows = [
        (
            record.date,
            record.student.roll_number,
            record.student.user.get_full_name(),
            record.student.course.name,
            record.subject.name,
            "Present" if record.present else "Absent"
        )
        for record in records
    ]

    return render(request, "management/records.html", {
        "title": "Attendance Records",
        "headers": [
            "Date", "Roll Number", "Student",
            "Course", "Subject", "Status"
        ],
        "rows": rows,
    })


@role_required(User.Role.HOD)
def hod_result_list(request):

    results = Result.objects.select_related(
        "student__user",
        "subject"
    )

    rows = [
        (
            item.student.roll_number,
            item.student.user.get_full_name(),
            item.subject.name,
            item.examination,
            item.marks_obtained,
            item.maximum_marks
        )
        for item in results
    ]

    return render(request, "management/records.html", {
        "title": "Examination Results",
        "headers": [
            "Roll Number", "Student", "Subject",
            "Examination", "Marks", "Maximum Marks"
        ],
        "rows": rows,
    })



@role_required(User.Role.STAFF)
def staff_dashboard(request):

    profile = get_object_or_404(
        StaffProfile,
        user=request.user
    )

    subjects = profile.subjects.select_related("course")

    context = {
        "profile": profile,
        "subjects": subjects,

        "student_count": StudentProfile.objects.filter(
            course__in=subjects.values("course_id")
        ).distinct().count(),

        "pending_leaves": LeaveApplication.objects.filter(
            user=request.user,
            status=LeaveApplication.Status.PENDING
        ).count(),
    }

    return render(
        request,
        "management/staff_dashboard.html",
        context
    )


@role_required(User.Role.STAFF)
def take_attendance(request):

    profile = get_object_or_404(
        StaffProfile,
        user=request.user
    )

    subjects = profile.subjects.select_related("course")

    selected_subject = None
    students = StudentProfile.objects.none()

    selected_date = (
        request.GET.get("date")
        or request.POST.get("date")
        or ""
    )

    subject_id = (
        request.GET.get("subject")
        or request.POST.get("subject")
    )

    if subject_id:

        selected_subject = get_object_or_404(
            subjects,
            pk=subject_id
        )

        students = StudentProfile.objects.filter(
            course=selected_subject.course
        ).select_related("user")

    if request.method == "POST":

        attendance_date = parse_date(selected_date)

        if not selected_subject or not attendance_date:

            messages.error(request, "Select a valid subject and date.")

        else:

            present_ids = set(
                request.POST.getlist("present_students")
            )

            with transaction.atomic():

                for student in students:

                    Attendance.objects.update_or_create(
                        subject=selected_subject,
                        student=student,
                        date=attendance_date,

                        defaults={
                            "present": str(student.pk) in present_ids,
                            "recorded_by": request.user,
                        },
                    )

            messages.success(request, "Attendance saved.")

            return redirect(
                f"/staff/attendance/?subject={selected_subject.pk}"
                f"&date={attendance_date.isoformat()}"
            )

    return render(request, "management/take_attendance.html", {
        "subjects": subjects,
        "selected_subject": selected_subject,
        "students": students,
        "selected_date": selected_date,
    })


@role_required(User.Role.STAFF)
def add_result(request):

    profile = get_object_or_404(
        StaffProfile,
        user=request.user
    )

    form = ResultForm(
        request.POST or None,
        staff_profile=profile
    )

    if request.method == "POST" and form.is_valid():

        result = form.save(commit=False)
        result.added_by = request.user
        result.save()

        messages.success(request, "Result saved successfully.")

        return redirect("staff_dashboard")

    return render(request, "management/form.html", {
        "title": "Add Examination Result",
        "form": form,
        "help_text": "Select a subject and a student enrolled in its course.",
    })


@role_required(User.Role.STAFF)
def staff_leave(request):

    form = LeaveApplicationForm(request.POST or None)

    if request.method == "POST" and form.is_valid():

        leave = form.save(commit=False)
        leave.user = request.user
        leave.save()

        messages.success(request, "Leave application submitted.")

        return redirect("staff_dashboard")

    return render(request, "management/form.html", {
        "title": "Apply for Leave",
        "form": form,
    })


@role_required(User.Role.STAFF)
def staff_feedback(request):

    form = FeedbackForm(request.POST or None)

    if request.method == "POST" and form.is_valid():

        item = form.save(commit=False)
        item.user = request.user
        item.save()

        messages.success(request, "Feedback submitted.")

        return redirect("staff_dashboard")

    return render(request, "management/form.html", {
        "title": "Send Feedback",
        "form": form,
    })



@role_required(User.Role.STUDENT)
def student_dashboard(request):

    profile = get_object_or_404(
        StudentProfile,
        user=request.user
    )

    attendance = Attendance.objects.filter(student=profile)

    total = attendance.count()
    present = attendance.filter(present=True).count()

    percentage = (
        round((present / total) * 100, 1)
        if total else 0
    )

    context = {
        "profile": profile,
        "total_attendance": total,
        "present_count": present,
        "attendance_percentage": percentage,

        "result_count": Result.objects.filter(
            student=profile
        ).count(),

        "pending_leaves": LeaveApplication.objects.filter(
            user=request.user,
            status=LeaveApplication.Status.PENDING
        ).count(),
    }

    return render(
        request,
        "management/student_dashboard.html",
        context
    )


@role_required(User.Role.STUDENT)
def student_attendance(request):

    profile = get_object_or_404(
        StudentProfile,
        user=request.user
    )

    records = Attendance.objects.filter(
        student=profile
    ).select_related("subject").order_by("-date")

    rows = [
        (
            item.date,
            item.subject.name,
            "Present" if item.present else "Absent"
        )
        for item in records
    ]

    return render(request, "management/records.html", {
        "title": "My Attendance",
        "headers": ["Date", "Subject", "Status"],
        "rows": rows,
    })


@role_required(User.Role.STUDENT)
def student_results(request):

    profile = get_object_or_404(
        StudentProfile,
        user=request.user
    )

    results = Result.objects.filter(
        student=profile
    ).select_related("subject")

    rows = [
        (
            item.subject.name,
            item.examination,
            item.marks_obtained,
            item.maximum_marks
        )
        for item in results
    ]

    return render(request, "management/records.html", {
        "title": "My Examination Results",
        "headers": [
            "Subject", "Examination", "Marks Obtained", "Maximum Marks"
        ],
        "rows": rows,
    })


@role_required(User.Role.STUDENT)
def student_leave(request):

    form = LeaveApplicationForm(request.POST or None)

    if request.method == "POST" and form.is_valid():

        leave = form.save(commit=False)
        leave.user = request.user
        leave.save()

        messages.success(request, "Leave application submitted.")

        return redirect("student_dashboard")

    return render(request, "management/form.html", {
        "title": "Apply for Leave",
        "form": form,
    })


@role_required(User.Role.STUDENT)
def student_feedback(request):

    form = FeedbackForm(request.POST or None)

    if request.method == "POST" and form.is_valid():

        item = form.save(commit=False)
        item.user = request.user
        item.save()

        messages.success(request, "Feedback submitted.")

        return redirect("student_dashboard")

    return render(request, "management/form.html", {
        "title": "Send Feedback",
        "form": form,
    })


@role_required(User.Role.STUDENT)
def student_leave_history(request):

    leaves = LeaveApplication.objects.filter(
        user=request.user
    )

    return render(request, "management/leave_list.html", {
        "title": "My Leave Applications",
        "leaves": leaves,
        "can_review": False,
    })

Explanation:

  • dashboard redirects users to their respective dashboards based on their roles.
  • HOD views manage student accounts, staff accounts, courses, subjects, attendance, results, leave, and feedback.
  • Staff views handle assigned subjects, attendance, results, leave, and feedback.
  • Student views display academic information and handle leave and feedback submissions.
  • transaction.atomic() ensures that related database operations are completed together.
  • update_or_create() updates existing attendance records or creates new ones.

9. Configuring Application URLs

Create urls.py inside the management application to connect the application views with their respective URLs.

Python
from django.contrib.auth import views as auth_views
from django.urls import path

from . import views


urlpatterns = [

    path(
        "login/",
        auth_views.LoginView.as_view(
            template_name="registration/login.html"
        ),
        name="login"
    ),

    path(
        "logout/",
        auth_views.LogoutView.as_view(),
        name="logout"
    ),

    path("", views.dashboard, name="dashboard"),

    # HOD URLs

    path("hod/", views.hod_dashboard, name="hod_dashboard"),

    path("hod/students/", views.student_list, name="student_list"),
    path("hod/students/add/", views.add_student, name="add_student"),

    path("hod/staff/", views.staff_list, name="staff_list"),
    path("hod/staff/add/", views.add_staff, name="add_staff"),

    path("hod/courses/", views.course_list, name="course_list"),
    path("hod/courses/add/", views.add_course, name="add_course"),

    path("hod/subjects/", views.subject_list, name="subject_list"),
    path("hod/subjects/add/", views.add_subject, name="add_subject"),

    path("hod/leaves/", views.hod_leave_list, name="hod_leave_list"),

    path(
        "hod/leaves/<int:pk>/review/",
        views.review_leave,
        name="review_leave"
    ),

    path("hod/feedback/", views.hod_feedback_list, name="hod_feedback_list"),

    path(
        "hod/feedback/<int:pk>/reply/",
        views.reply_feedback,
        name="reply_feedback"
    ),

    path(
        "hod/attendance/",
        views.hod_attendance_list,
        name="hod_attendance_list"
    ),

    path("hod/results/", views.hod_result_list, name="hod_result_list"),

    # Staff URLs

    path("staff/", views.staff_dashboard, name="staff_dashboard"),

    path(
        "staff/attendance/",
        views.take_attendance,
        name="take_attendance"
    ),

    path("staff/results/add/", views.add_result, name="add_result"),

    path("staff/leave/", views.staff_leave, name="staff_leave"),

    path("staff/feedback/", views.staff_feedback, name="staff_feedback"),

    # Student URLs

    path("student/", views.student_dashboard, name="student_dashboard"),

    path(
        "student/attendance/",
        views.student_attendance,
        name="student_attendance"
    ),

    path("student/results/", views.student_results, name="student_results"),

    path("student/leave/", views.student_leave, name="student_leave"),

    path(
        "student/leave/history/",
        views.student_leave_history,
        name="student_leave_history"
    ),

    path(
        "student/feedback/",
        views.student_feedback,
        name="student_feedback"
    ),
]

Explanation:

  • path() connects URL patterns with their corresponding views.
  • LoginView and LogoutView provide authentication endpoints.
  • Separate URL groups maintain HOD, staff, and student functionality.
  • Named URLs simplify redirects and navigation.

Now open college_portal/urls.py and connect the application routes.

Python
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("management.urls")),
]

Explanation:

  • Admin route provides access to Django's administration panel.
  • include() connects the application-level URL configuration with the main project.

10. Registering Models in Django Admin

Open admin.py inside the management application. Register the models to manage college records through the Django administration interface.

Python
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin

from .models import (
    CollegeUser,
    Course,
    StaffProfile,
    StudentProfile,
    Subject,
    Attendance,
    LeaveApplication,
    Result,
    Feedback,
)


@admin.register(CollegeUser)
class CollegeUserAdmin(UserAdmin):

    fieldsets = UserAdmin.fieldsets + (
        ("College Role", {"fields": ("role",)}),
    )

    add_fieldsets = UserAdmin.add_fieldsets + (
        ("College Role", {"fields": ("role",)}),
    )

    list_display = (
        "username",
        "email",
        "first_name",
        "last_name",
        "role",
        "is_active",
    )

    list_filter = ("role", "is_active", "is_staff")


admin.site.register([
    Course,
    StaffProfile,
    StudentProfile,
    Subject,
    Attendance,
    LeaveApplication,
    Result,
    Feedback,
])

Explanation:

  • CollegeUserAdmin extends Django's default user administration interface.
  • list_display specifies the columns displayed in the admin panel.
  • list_filter allows administrators to filter accounts by role and status.
  • admin.site.register() makes the remaining models available for management.

11. Create HTML Templates

Create a templates directory in the project root. Inside it, create registration and management directories. Application uses a common base template to maintain navigation, styling, and messages across all dashboards.

1. base.html : Create templates/base.html and add the following code:

Python
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>{% block title %}College Management System{% endblock %}</title>

    <style>
        * { box-sizing: border-box; }

        body {
            margin: 0;
            font-family: Arial, sans-serif;
            background: #f4f6fa;
            color: #1f2937;
        }

        header {
            background: #172554;
            color: white;
            padding: 18px 5%;
            display: flex;
            justify-content: space-between;
        }

        header a {
            color: white;
            text-decoration: none;
        }

        main {
            max-width: 1100px;
            margin: 30px auto;
            padding: 0 18px;
        }

        .nav {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            margin-bottom: 22px;
        }

        .nav a, .btn {
            background: #1d4ed8;
            color: white;
            padding: 10px 14px;
            border: none;
            border-radius: 6px;
            text-decoration: none;
            cursor: pointer;
            display: inline-block;
        }

        .secondary {
            background: #475569;
        }

        .danger {
            background: #b91c1c;
        }

        .card {
            background: white;
            border: 1px solid #e5e7eb;
            border-radius: 10px;
            padding: 20px;
            margin-bottom: 18px;
        }

        .grid {
            display: grid;
            grid-template-columns: repeat(
                auto-fit, minmax(180px, 1fr)
            );
            gap: 14px;
        }

        .metric {
            font-size: 28px;
            font-weight: bold;
            color: #1d4ed8;
            margin-top: 8px;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            background: white;
        }

        th, td {
            padding: 12px;
            border-bottom: 1px solid #e5e7eb;
            text-align: left;
        }

        th {
            background: #eff6ff;
        }

        input, select, textarea {
            width: 100%;
            max-width: 560px;
            padding: 10px;
            border: 1px solid #cbd5e1;
            border-radius: 6px;
        }

        input[type="checkbox"] {
            width: auto;
        }

        textarea {
            min-height: 100px;
        }

        .messages {
            list-style: none;
            padding: 0;
        }

        .messages li {
            background: #e0f2fe;
            padding: 12px;
            margin-bottom: 8px;
            border-radius: 6px;
        }

        .muted {
            color: #64748b;
        }

        .inline {
            display: inline-block;
        }

        @media(max-width: 600px) {
            header {
                flex-direction: column;
                gap: 12px;
            }

            table {
                font-size: 13px;
            }
        }
    </style>
</head>

<body>

<header>
    <div>
        <a href="{% url 'dashboard' %}">
            <strong>College Management System</strong>
        </a>
    </div>

    <div>
        {% if request.user.is_authenticated %}

            {{ request.user.get_full_name|default:request.user.username }}

            <form class="inline" method="post"
                  action="{% url 'logout' %}">
                {% csrf_token %}

                <button class="btn secondary" type="submit">
                    Logout
                </button>
            </form>

        {% else %}

            <a href="{% url 'login' %}">Login</a>

        {% endif %}
    </div>
</header>

<main>

    {% if request.user.is_authenticated %}

    <nav class="nav">

        {% if request.user.role == "HOD" %}

            <a href="{% url 'hod_dashboard' %}">Dashboard</a>
            <a href="{% url 'student_list' %}">Students</a>
            <a href="{% url 'staff_list' %}">Staff</a>
            <a href="{% url 'course_list' %}">Courses</a>
            <a href="{% url 'subject_list' %}">Subjects</a>
            <a href="{% url 'hod_leave_list' %}">Leave</a>
            <a href="{% url 'hod_feedback_list' %}">Feedback</a>
            <a href="{% url 'hod_attendance_list' %}">Attendance</a>
            <a href="{% url 'hod_result_list' %}">Results</a>

        {% elif request.user.role == "STAFF" %}

            <a href="{% url 'staff_dashboard' %}">Dashboard</a>
            <a href="{% url 'take_attendance' %}">Attendance</a>
            <a href="{% url 'add_result' %}">Add Result</a>
            <a href="{% url 'staff_leave' %}">Apply Leave</a>
            <a href="{% url 'staff_feedback' %}">Feedback</a>

        {% elif request.user.role == "STUDENT" %}

            <a href="{% url 'student_dashboard' %}">Dashboard</a>
            <a href="{% url 'student_attendance' %}">Attendance</a>
            <a href="{% url 'student_results' %}">Results</a>
            <a href="{% url 'student_leave' %}">Apply Leave</a>
            <a href="{% url 'student_leave_history' %}">Leave History</a>
            <a href="{% url 'student_feedback' %}">Feedback</a>

        {% endif %}

    </nav>

    {% endif %}

    {% if messages %}
        <ul class="messages">
            {% for message in messages %}
                <li>{{ message }}</li>
            {% endfor %}
        </ul>
    {% endif %}

    {% block content %}
    {% endblock %}

</main>

</body>
</html>

Explanation:

  • base.html provides the shared layout for all application pages.
  • Navigation menu changes according to the logged-in user's role.
  • Django template inheritance allows individual pages to reuse the same layout.
  • Messages display the results of operations such as creating records or submitting leave requests.

2. Login Page: Create templates/registeration/login.html.

Python
{% extends "base.html" %}

{% block title %}
Login - College Management System
{% endblock %}

{% block content %}

<div class="card">

    <h1>Login</h1>

    <p class="muted">
        Enter your registered username and password.
    </p>

    <form method="post">

        {% csrf_token %}

        {{ form.as_p }}

        <button class="btn" type="submit">
            Login
        </button>

    </form>

</div>

{% endblock %}

Explanation:

  • LoginView provides Django's authentication functionality.
  • form.as_p displays the username and password fields.
  • csrf_token protects the submitted form against CSRF attacks.

3. HOD Dashboard: Create templates/management/hod_dashboard.html

Python
{% extends "base.html" %}

{% block title %}
HOD Dashboard
{% endblock %}

{% block content %}

<h1>HOD Dashboard</h1>

<p class="muted">
    Manage academic records and college activities.
</p>

<div class="grid">

    <div class="card">
        Students
        <div class="metric">{{ student_count }}</div>
    </div>

    <div class="card">
        Staff
        <div class="metric">{{ staff_count }}</div>
    </div>

    <div class="card">
        Courses
        <div class="metric">{{ course_count }}</div>
    </div>

    <div class="card">
        Subjects
        <div class="metric">{{ subject_count }}</div>
    </div>

    <div class="card">
        Pending Leave Requests
        <div class="metric">{{ pending_leaves }}</div>
    </div>

</div>

<div class="card">

    <h2>Recent Leave Applications</h2>

    {% for leave in recent_leaves %}

        <p>
            {{ leave.user.username }} -
            {{ leave.start_date }} to {{ leave.end_date }}
            - {{ leave.get_status_display }}
        </p>

    {% empty %}

        <p>No leave applications found.</p>

    {% endfor %}

    <a href="{% url 'hod_leave_list' %}" class="btn">
        Review Applications
    </a>

</div>

{% endblock %}

Explanation:

  • Displays student, staff, course, and subject counts.
  • Shows pending leave applications.
  • Provides access to administrative operations.

4. Staff Dashboard: Create templates/management/staff_dashboard.html

Python
{% extends "base.html" %}

{% block title %}
Staff Dashboard
{% endblock %}

{% block content %}

<h1>Staff Dashboard</h1>

<div class="card">

    <p>
        <strong>Department:</strong>
        {{ profile.department }}
    </p>

    <p>
        <strong>Students:</strong>
        {{ student_count }}
    </p>

    <p>
        <strong>Pending Leave:</strong>
        {{ pending_leaves }}
    </p>

</div>

<div class="card">

    <h2>Assigned Subjects</h2>

    <table>

        <thead>
            <tr>
                <th>Subject</th>
                <th>Code</th>
                <th>Course</th>
            </tr>
        </thead>

        <tbody>

            {% for subject in subjects %}

            <tr>
                <td>{{ subject.name }}</td>
                <td>{{ subject.code }}</td>
                <td>{{ subject.course.name }}</td>
            </tr>

            {% empty %}

            <tr>
                <td colspan="3">No subjects assigned.</td>
            </tr>

            {% endfor %}

        </tbody>

    </table>

</div>

{% endblock %}

Explanation:

  • Displays staff department and student statistics.
  • Lists subjects assigned by the HOD.
  • Provides access to attendance, results, and leave operations through navigation.

5. Student Dashboard: Create templates/management/student_dashboard.html.

Python
{% extends "base.html" %}

{% block title %}
Student Dashboard
{% endblock %}

{% block content %}

<h1>Student Dashboard</h1>

<div class="card">

    <p>
        <strong>Name:</strong>
        {{ request.user.get_full_name }}
    </p>

    <p>
        <strong>Roll Number:</strong>
        {{ profile.roll_number }}
    </p>

    <p>
        <strong>Course:</strong>
        {{ profile.course.name }}
    </p>

    <p>
        <strong>Admission Year:</strong>
        {{ profile.admission_year }}
    </p>

</div>

<div class="grid">

    <div class="card">
        Total Attendance
        <div class="metric">{{ total_attendance }}</div>
    </div>

    <div class="card">
        Present
        <div class="metric">{{ present_count }}</div>
    </div>

    <div class="card">
        Attendance Percentage
        <div class="metric">{{ attendance_percentage }}%</div>
    </div>

    <div class="card">
        Results Published
        <div class="metric">{{ result_count }}</div>
    </div>

    <div class="card">
        Pending Leave
        <div class="metric">{{ pending_leaves }}</div>
    </div>

</div>

{% endblock %}

Explanation:

  • Displays student profile and academic information.
  • Calculates attendance statistics through the corresponding view.
  • Shows the number of published examination results and pending leave requests.

12. Creating Generic Form Template

Several application operations use reusable templates rather than separate HTML files.

1. Generic Form Template: Create templates/management/form.html

Python
{% extends "base.html" %}

{% block content %}

<div class="card">

    <h1>{{ title }}</h1>

    {% if help_text %}
        <p class="muted">{{ help_text }}</p>
    {% endif %}

    <form method="post">

        {% csrf_token %}

        {{ form.as_p }}

        <button class="btn" type="submit">
            Save
        </button>

    </form>

</div>

{% endblock %}

Explanation:

  • Displays forms for student, staff, course, subject, leave, and feedback operations.
  • form.as_p renders the fields and validation errors.
  • Same template reduces repeated HTML code.

2. Create Records Template: Create templates/management/records.html.

Python
{% extends "base.html" %}

{% block content %}

<div class="card">

    <h1>{{ title }}</h1>

    {% if add_url %}

        <a href="{% url add_url %}" class="btn">
            Add New
        </a>

    {% endif %}

    <div style="overflow-x:auto">

        <table>

            <thead>

                <tr>

                    {% for heading in headers %}

                        <th>{{ heading }}</th>

                    {% endfor %}

                </tr>

            </thead>

            <tbody>

                {% for row in rows %}

                    <tr>

                        {% for value in row %}

                            <td>{{ value }}</td>

                        {% endfor %}

                    </tr>

                {% empty %}

                    <tr>
                        <td colspan="20">No records found.</td>
                    </tr>

                {% endfor %}

            </tbody>

        </table>

    </div>

</div>

{% endblock %}

Explanation:

  • Displays students, staff, courses, subjects, attendance, and results.
  • Dynamically generates table headings and rows.
  • Displays an Add New option when the corresponding view supports record creation.

3. Attendance Template: Create templates/management/take_attendance.html.

Python
{% extends "base.html" %}

{% block content %}

<div class="card">

    <h1>Take Attendance</h1>

    <form method="get">

        <p>
            <label>Subject</label>

            <select name="subject" required>

                <option value="">Select Subject</option>

                {% for subject in subjects %}

                    <option value="{{ subject.pk }}"
                        {% if selected_subject and selected_subject.pk == subject.pk %}
                            selected
                        {% endif %}>

                        {{ subject.name }} - {{ subject.course.name }}

                    </option>

                {% endfor %}

            </select>

        </p>

        <p>
            <label>Date</label>

            <input
                type="date"
                name="date"
                value="{{ selected_date }}"
                required
            >
        </p>

        <button class="btn" type="submit">
            Load Students
        </button>

    </form>

</div>

{% if selected_subject %}

<div class="card">

    <h2>{{ selected_subject.name }}</h2>

    <p class="muted">
        Select the students who are present.
        Unchecked students will be marked absent.
    </p>

    <form method="post">

        {% csrf_token %}

        <input
            type="hidden"
            name="subject"
            value="{{ selected_subject.pk }}"
        >

        <input
            type="hidden"
            name="date"
            value="{{ selected_date }}"
        >

        <table>

            <thead>
                <tr>
                    <th>Roll Number</th>
                    <th>Student</th>
                    <th>Present</th>
                </tr>
            </thead>

            <tbody>

                {% for student in students %}

                <tr>

                    <td>{{ student.roll_number }}</td>

                    <td>{{ student.user.get_full_name }}</td>

                    <td>
                        <input
                            type="checkbox"
                            name="present_students"
                            value="{{ student.pk }}"
                        >
                    </td>

                </tr>

                {% empty %}

                <tr>
                    <td colspan="3">No enrolled students found.</td>
                </tr>

                {% endfor %}

            </tbody>

        </table>

        {% if students %}

            <br>

            <button class="btn" type="submit">
                Save Attendance
            </button>

        {% endif %}

    </form>

</div>

{% endif %}

{% endblock %}

Explanation:

  • Staff member selects a subject and attendance date.
  • Application retrieves students enrolled in the selected course.
  • Checkboxes identify present students.
  • Unchecked students are recorded as absent.

4. Leave Application Template: Create templates/management/leave_list.html.

Python
{% extends "base.html" %}

{% block content %}

<div class="card">

    <h1>{{ title }}</h1>

    <table>

        <thead>
            <tr>
                <th>User</th>
                <th>Dates</th>
                <th>Reason</th>
                <th>Status</th>

                {% if can_review %}
                    <th>Action</th>
                {% endif %}

            </tr>
        </thead>

        <tbody>

            {% for leave in leaves %}

            <tr>

                <td>
                    {{ leave.user.username }}
                </td>

                <td>
                    {{ leave.start_date }} to {{ leave.end_date }}
                </td>

                <td>
                    {{ leave.reason }}
                </td>

                <td>
                    {{ leave.get_status_display }}
                </td>

                {% if can_review %}

                <td>

                    {% if leave.status == "PENDING" %}

                    <form
                        method="post"
                        action="{% url 'review_leave' leave.pk %}"
                    >

                        {% csrf_token %}

                        <button
                            class="btn"
                            name="action"
                            value="approve"
                        >
                            Approve
                        </button>

                        <button
                            class="btn danger"
                            name="action"
                            value="reject"
                        >
                            Reject
                        </button>

                    </form>

                    {% else %}

                        Reviewed

                    {% endif %}

                </td>

                {% endif %}

            </tr>

            {% empty %}

            <tr>
                <td colspan="5">No leave applications found.</td>
            </tr>

            {% endfor %}

        </tbody>

    </table>

</div>

{% endblock %}

Explanation:

  • Displays leave applications and their current status.
  • HOD can approve or reject pending requests.
  • Students can view their own leave history.

5. Feedback Template: Create templates/management/feedback_list.html.

Python
{% extends "base.html" %}

{% block content %}

<div class="card">

    <h1>{{ title }}</h1>

    {% for item in feedback_items %}

        <div class="card">

            <p>
                <strong>{{ item.user.username }}</strong>
                - {{ item.created_at }}
            </p>

            <p>
                {{ item.message }}
            </p>

            <p>
                <strong>Response:</strong>
                {{ item.response|default:"Not answered yet" }}
            </p>

            <a
                href="{% url 'reply_feedback' item.pk %}"
                class="btn"
            >
                Reply
            </a>

        </div>

    {% empty %}

        <p>No feedback submitted yet.</p>

    {% endfor %}

</div>

{% endblock %}

Explanation:

  • Displays feedback submitted by students and staff.
  • HOD can open individual messages and submit responses.
  • Responses are stored in the Feedback model.

13. Creating Demonstration Accounts and Sample Data

Create the following directory structure inside management:

Create seed_demo.py to automatically populate the database with sample users and academic records.

Python
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
from django.utils import timezone

from management.models import (
    Course,
    StaffProfile,
    StudentProfile,
    Subject,
    Attendance,
    Result,
)

User = get_user_model()


class Command(BaseCommand):

    help = "Create sample college management data."

    def handle(self, *args, **options):

        course, _ = Course.objects.get_or_create(
            code="BCA",
            defaults={
                "name": "Bachelor of Computer Applications"
            }
        )

        hod, created = User.objects.get_or_create(
            username="hod",
            defaults={
                "first_name": "Harsh",
                "last_name": "Mehta",
                "email": "hod@example.com",
                "role": User.Role.HOD,
            }
        )

        if created:
            hod.set_password("HOD@12345")
            hod.save()
        else:
            hod.role = User.Role.HOD
            hod.save(update_fields=["role"])

        staff, created = User.objects.get_or_create(
            username="staff1",
            defaults={
                "first_name": "Asha",
                "last_name": "Sharma",
                "email": "asha@example.com",
                "role": User.Role.STAFF,
            }
        )

        if created:
            staff.set_password("Staff@12345")
            staff.save()
        else:
            staff.role = User.Role.STAFF
            staff.save(update_fields=["role"])

        staff_profile, _ = StaffProfile.objects.get_or_create(
            user=staff,
            defaults={"department": "Computer Science"}
        )

        student, created = User.objects.get_or_create(
            username="student1",
            defaults={
                "first_name": "Riya",
                "last_name": "Verma",
                "email": "riya@example.com",
                "role": User.Role.STUDENT,
            }
        )

        if created:
            student.set_password("Student@12345")
            student.save()
        else:
            student.role = User.Role.STUDENT
            student.save(update_fields=["role"])

        student_profile, _ = StudentProfile.objects.get_or_create(
            user=student,
            defaults={
                "roll_number": "BCA001",
                "course": course,
                "admission_year": timezone.localdate().year,
            }
        )

        subject, _ = Subject.objects.get_or_create(
            code="BCA101",
            defaults={
                "name": "Programming Fundamentals",
                "course": course,
                "staff": staff_profile,
            }
        )

        if subject.staff_id is None:
            subject.staff = staff_profile
            subject.save(update_fields=["staff"])

        Attendance.objects.get_or_create(
            subject=subject,
            student=student_profile,
            date=timezone.localdate(),
            defaults={
                "present": True,
                "recorded_by": staff,
            }
        )

        Result.objects.get_or_create(
            student=student_profile,
            subject=subject,
            examination="Unit Test 1",
            defaults={
                "marks_obtained": 42,
                "maximum_marks": 50,
                "added_by": staff,
            }
        )

        self.stdout.write(
            self.style.SUCCESS("Demo data created successfully.")
        )

        self.stdout.write("HOD: hod / HOD@12345")
        self.stdout.write("Staff: staff1 / Staff@12345")
        self.stdout.write("Student: student1 / Student@12345")

Explanation:

  • Creates one HOD, staff member, and student account.
  • Creates a sample BCA course and Programming Fundamentals subject.
  • Assigns the subject to the staff member.
  • Adds sample attendance and examination result records.
  • get_or_create() prevents duplicate sample records when the command is executed again.

14. Creating Database Tables

After creating the models, generate and apply database migrations.

Run the commands from the direcotry containing manage.py.

python manage.py makemigrations management
python manage.py migrate

Explanation:

  • makemigrations generates migration files based on model changes.
  • migrate applies migrations and creates the required SQLite database tables.

15. Generate Sample Data and Run Application

Execute the custom management command to populate the database.

python manage.py seed_demo

Start Django Development server.

python manage.py runserver

Project Output

Final application provides separate interfaces for HOD, staff, and students.

1. HOD Dashboard

Displays student and staff counts, academic information, pending leave requests, attendance records, and examination results.

Screenshot_2026-11-03_10-20-05

2. Staff Dashboard

Displays assigned subjects and provides access to attendance recording, examination results, leave applications, and feedback.

Screenshot_2026-11-03_10-22-04


3. Student Dashboard

Displays student information, attendance percentage, examination results, and leave application status.

Screenshot_2026-11-03_10-22-37
Comment