Project Overview
The Student-Management system centralizes student data, course catalogs, enrollments and grading in a single, extensible platform. It exposes RESTful APIs and a web UI (or CLI) to automate administrative workflows for schools, colleges and training centers.
Key Features
- Student CRUD: register, update, suspend and delete student records
- Course Catalog: define courses, sections, schedules and instructors
- Enrollment Management: enroll students, handle waitlists and capacity constraints
- Gradebook & Reporting: record grades, generate transcripts and performance analytics
- Authentication & Roles: secure access with administrator, instructor and student roles
- Extensibility: plugin hooks for custom reports, notifications and data exports
Typical Use Cases
- Onboarding new batches: bulk-import student data, assign core courses
- Grading cycle: instructors submit grades; admin generates official transcripts
- Real-time dashboards: monitor enrollment trends and course fill rates
- Data integration: sync with ERP/payroll, export CSV/JSON for BI tools
Architecture Overview
- Backend: REST API layer managing business logic and data validation
- Database: relational (e.g., PostgreSQL/MySQL) or document store (e.g., MongoDB)
- Frontend: web client built on React/Vue.js or CLI scripts for automation
- Authentication: JWT/OAuth2 or session-based flows
- Deployment: Dockerized services or cloud-native containers
Value Proposition
- Streamlines administrative tasks, reducing manual errors
- Provides actionable insights via built-in reporting
- Scales with institution size through modular design
- Offers clear extension points for custom workflows and integrations
Getting Started
Follow these steps to install dependencies, configure the environment, run migrations, create a superuser, and start the development server.
1. Clone the Repository
git clone https://github.com/MrRoy2246/Student-Management.git
cd Student-Management
2. Create & Activate Virtual Environment
python3 -m venv venv
# macOS/Linux
source venv/bin/activate
# Windows (PowerShell)
venv\Scripts\Activate.ps1
3. Install Dependencies
pip install --upgrade pip
pip install -r requirements.txt
4. Configure Environment
By default the project uses SQLite (db.sqlite3
). To override settings, set environment variables before running any Django command:
export DJANGO_SECRET_KEY="your-secret-key"
export DJANGO_DEBUG=True
export DJANGO_ALLOWED_HOSTS="127.0.0.1,localhost"
On Windows (PowerShell):
$env:DJANGO_SECRET_KEY="your-secret-key"
$env:DJANGO_DEBUG="True"
$env:DJANGO_ALLOWED_HOSTS="127.0.0.1,localhost"
Adjust student_course_mgmt/settings.py
if you need a different database or custom settings.
5. Apply Database Migrations
python manage.py migrate
This creates the required tables in db.sqlite3
.
6. Create a Superuser
python manage.py createsuperuser
Follow the prompts to set username, email, and password. This account lets you access the Django admin at /admin/
.
7. Start the Development Server
python manage.py runserver
Visit http://127.0.0.1:8000 to verify the application is running. The admin interface is available at http://127.0.0.1:8000/admin/.
Core Concepts & Architecture
This section describes how the Student-Management system organizes its custom authentication, role-based access, app boundaries, and core data relationships.
1. Custom User Model
The accounts
app defines a custom User
model extending AbstractBaseUser
with built-in roles and a dedicated manager.
Key Elements
- Fields:
email
(unique),first_name
,last_name
,role
- Roles:
STUDENT
TEACHER
ADMIN
ADVISING_ADMIN
ACCOUNT_CREATOR_ADMIN
- Manager:
CustomUserManager
handlescreate_user
andcreate_superuser
.
Usage Example
# accounts/models.py
from accounts.models import User
# Create a student user
student = User.objects.create_user(
email='alice@student.edu',
password='securePass123',
first_name='Alice',
last_name='Johnson',
role=User.STUDENT
)
# Create a superuser
admin = User.objects.create_superuser(
email='admin@school.edu',
password='superSecure!',
first_name='Super',
last_name='User'
)
2. Role-Based Permissions
The accounts/permission.py
file provides DRF permission classes enforcing role checks at the view and object level.
Common Permission Classes
IsAdmin
IsAdvisingAdmin
IsAccountCreator
IsStudent
ReadOnly
Applying Permissions
# accounts/views.py
from rest_framework import viewsets
from accounts.models import User
from accounts.serializers import UserSerializer
from accounts.permission import IsAdmin, ReadOnly
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAdmin|ReadOnly]
3. App Boundaries & URL Routing
The project splits functionality into coherent Django apps:
accounts
– authentication, user registration, rolesdepartments
– department CRUD, active student countsstudents
– student profilesteachers
– teacher profilescourses
– courses and sections management
Root URL Configuration
# student_course_mgmt/urls.py
from django.urls import path, include
from django.contrib import admin
urlpatterns = [
path('admin/', admin.site.urls),
path('api/accounts/', include('accounts.urls')),
path('api/departments/', include('departments.urls')),
path('api/students/', include('students.urls')),
path('api/teachers/', include('teachers.urls')),
path('api/courses/', include('courses.urls')),
]
4. Data Model Relationships
User ↔ Profiles
- One-to-one:
User
↔StudentProfile
(students/models.py
) - One-to-one:
User
↔TeacherProfile
(teachers/models.py
)
Department ↔ StudentProfile
Department
(one) →StudentProfile
(many)- Method:
Department.active_student_count()
Course ↔ Sections ↔ Teachers
Course
→Section
(one-to-many)Section.instructor
→TeacherProfile
Relationship Examples
# Fetch a student's department and active student count
from students.models import StudentProfile
from departments.models import Department
student_profile = StudentProfile.objects.get(user__email='alice@student.edu')
department = student_profile.department
print(department.active_student_count())
# Assign a teacher to a course section
from courses.models import Section
from teachers.models import TeacherProfile
teacher = TeacherProfile.objects.get(user__email='prof.jones@school.edu')
section = Section.objects.get(id=42)
section.instructor = teacher
section.save()
This high-level view guides you through the core building blocks of the Student-Management system, highlighting where to extend authentication, permission rules, and data interactions.
REST API Guide
This guide describes each REST endpoint, its authentication, request/response shapes, and common workflows in the Student-Management project.
Accounts API
POST /accounts/register/
Create a new user. Restricts access to admin roles.
Permission class (accounts/permission.py)
from rest_framework.permissions import BasePermission
class IsSuperAdminOrAccountCreatorAdmin(BasePermission):
def has_permission(self, request, view):
return (
request.user.is_authenticated and
request.user.role in ['admin', 'account_creator_admin']
)
View configuration (accounts/views.py)
from rest_framework.generics import CreateAPIView
from .permissions import IsSuperAdminOrAccountCreatorAdmin
from .serializers import UserRegistrationSerializer
class UserRegistrationView(CreateAPIView):
serializer_class = UserRegistrationSerializer
permission_classes = [IsSuperAdminOrAccountCreatorAdmin]
URL pattern (accounts/urls.py)
from django.urls import path
from .views import UserRegistrationView
urlpatterns = [
path('register/', UserRegistrationView.as_view(), name='accounts-register'),
]
Example request
curl -X POST https://api.example.com/accounts/register/ \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{
"username":"jdoe",
"password":"SecureP@ss123",
"full_name":"John Doe",
"role":"student"
}'
Success response (201)
{
"id": 42,
"username": "jdoe",
"full_name": "John Doe",
"role": "student"
}
Student Profile API Endpoints
Expose student profiles; students manage their own, admins manage all.
URL configuration (students/urls.py)
from django.urls import path
from .views import (
StudentOwnProfileView,
StudentProfileListView,
StudentProfileDetailView
)
urlpatterns = [
path('profile/', StudentOwnProfileView.as_view(), name='own-profile'),
path('all-profile/', StudentProfileListView.as_view(), name='student-list'),
path('<int:pk>/', StudentProfileDetailView.as_view(), name='student-profile-detail'),
]
Endpoints
GET /students/profile/
• Serializer: StudentProfileSerializer
• Permission: IsStudent
• Returns the caller’s active profile.
PUT /students/profile/
• Updates address, phone_number.
GET /students/all-profile/
• Serializer: StudentProfileSerializer
• Permission: IsAdminOrAdvisingAdmin
• Lists all active profiles.
GET, PUT /students/{pk}/
• Serializer: AdminStudentProfileSerializer
• Permission: IsAdminOrAdvisingAdmin
• Operates on active profiles.
Examples
- Retrieve own profile
curl -H "Authorization: Bearer <token>" \
GET https://api.example.com/students/profile/
Response (200)
{
"id": 12,
"user_id": 34,
"user_name": "Jane Doe",
"student_id": "STU2025001",
"department_name": "Computer Science",
"department_code": "CS",
"date_of_birth": "2003-04-15",
"address": "123 Main St",
"phone_number": "+1234567890",
"enrollment_year": 2021
}
- Update own profile
curl -X PUT https://api.example.com/students/profile/ \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"address":"456 Elm St","phone_number":"+1987654321"}'
- List all profiles (admin)
curl -H "Authorization: Bearer <admin-token>" \
GET https://api.example.com/students/all-profile/
- Admin updates department
curl -X PUT https://api.example.com/students/12/ \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{"department":3}'
Tips
- StudentProfileSerializer marks user and student_id read-only.
- AdminStudentProfileSerializer allows nested user_name edits.
- Soft-delete by setting
is_active=False
excludes profiles from all endpoints.
Department API Endpoints
CRUD with soft-delete and role-based access.
URL configuration (departments/urls.py)
from django.urls import path
from .views import DepartmentListCreateView, DepartmentDetailView
urlpatterns = [
path('', DepartmentListCreateView.as_view(), name='department-list-create'),
path('<int:pk>/', DepartmentDetailView.as_view(), name='department-detail'),
]
Views (departments/views.py)
from rest_framework import generics, permissions
from .models import Department
from .serializers import DepartmentSerializer
from accounts.permission import IsSuperAdmin
class DepartmentListCreateView(generics.ListCreateAPIView):
queryset = Department.objects.filter(is_active=True)
serializer_class = DepartmentSerializer
def get_permissions(self):
if self.request.method == 'GET':
return [permissions.IsAuthenticated()]
return [IsSuperAdmin()]
class DepartmentDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Department.objects.filter(is_active=True)
serializer_class = DepartmentSerializer
def get_permissions(self):
if self.request.method == 'GET':
return [permissions.IsAuthenticated()]
return [IsSuperAdmin()]
def perform_destroy(self, instance):
instance.is_active = False
instance.save()
Examples
- List departments
GET /api/departments/ HTTP/1.1
Authorization: Token your_token_here
Response (200)
[
{ "id":1, "name":"Computer Science","code":"CS","student_count":120 },
…
]
- Create department (super-admin)
POST /api/departments/ HTTP/1.1
Authorization: Token superadmin_token
Content-Type: application/json
{ "name":"Mathematics","code":"MATH" }
Response (201)
{ "id":5, "name":"Mathematics","code":"MATH","student_count":0 }
- Soft-delete a department
DELETE /api/departments/5/ HTTP/1.1
Authorization: Token superadmin_token
Subsequent GETs omit this record.
Section API Endpoints
Manage course sections; enforce that teacher
has role “teacher.”
URL configuration (courses/urls.py)
from django.urls import path
from .views import SectionListCreateView, SectionDetailView
urlpatterns = [
path('sections/', SectionListCreateView.as_view(), name='section-list-create'),
path('sections/<int:pk>/', SectionDetailView.as_view(), name='section-detail'),
]
Serializer validation (courses/serializers.py)
from .models import Section
from rest_framework import serializers
class SectionSerializer(serializers.ModelSerializer):
course_name = serializers.CharField(source='course.name', read_only=True)
teacher_name = serializers.CharField(source='teacher.full_name', read_only=True)
class Meta:
model = Section
fields = [
'id','course','course_name',
'teacher','teacher_name',
'section','schedule','room','seats'
]
def validate_teacher(self, value):
if value.role != 'teacher':
raise serializers.ValidationError("Selected user is not a teacher.")
return value
Examples
- Create a section
curl -X POST https://api.example.com/sections/ \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"course":5,
"teacher":12,
"section":"A",
"schedule":"MWF 10:00-11:00",
"room":"B201",
"seats":25
}'
Success (201)
{
"id":8,
"course":5,
"course_name":"Intro to Algorithms",
"teacher":12,
"teacher_name":"Dr. Jane Smith",
"section":"A",
"schedule":"MWF 10:00-11:00",
"room":"B201",
"seats":25
}
- Validation error (non-teacher user)
{ "teacher":["Selected user is not a teacher."] }
Teacher Profile API Endpoints
Offer nested user info and controlled update semantics.
URL configuration (teachers/urls.py)
from django.urls import path
from .views import (
TeacherProfileView,
AdminTeacherProfileListView,
AdminTeacherProfileDetailView
)
urlpatterns = [
path('teachers/profile/', TeacherProfileView.as_view(), name='teacher-own-profile'),
path('admin/teachers/', AdminTeacherProfileListView.as_view(), name='admin-teacher-list'),
path('admin/teachers/<int:pk>/', AdminTeacherProfileDetailView.as_view(), name='admin-teacher-detail'),
]
Serializers (teachers/serializers.py)
TeacherProfileSerializer (read-only user fields)
class TeacherProfileSerializer(serializers.ModelSerializer):
user_id = serializers.IntegerField(source='user.id', read_only=True)
user_name = serializers.CharField(source='user.full_name', read_only=True)
class Meta:
model = TeacherProfile
fields = [
'id','user_id','user_name','teacher_id','designation',
'department','date_of_birth','address','phone_number',
'qualifications','experience_years','office_room_number'
]
read_only_fields = ['id','user_id']
def update(self, instance, validated_data):
validated_data.pop('user', None)
return super().update(instance, validated_data)
AdminTeacherProfileSerializer (editable full_name)
class AdminTeacherProfileSerializer(serializers.ModelSerializer):
user_id = serializers.IntegerField(source='user.id', read_only=True)
user_name = serializers.CharField(source='user.full_name')
class Meta:
model = TeacherProfile
fields = [
'id','user_id','user_name','teacher_id','designation',
'department','date_of_birth','address','phone_number',
'qualifications','experience_years','office_room_number'
]
read_only_fields = ['id','user_id']
def update(self, instance, validated_data):
user_data = validated_data.pop('user', {})
if 'full_name' in user_data:
instance.user.full_name = user_data['full_name']
instance.user.save()
return super().update(instance, validated_data)
Examples
- Regular user updates profile
curl -X PATCH https://api.example.com/teachers/profile/ \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"address":"789 Oak St","phone_number":"+1122334455"}'
- Admin lists all teachers
curl -H "Authorization: Bearer <admin-token>" \
GET https://api.example.com/admin/teachers/
- Admin updates full_name and designation
curl -X PUT https://api.example.com/admin/teachers/7/ \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{
"user":{ "full_name":"Dr. Emily Clark" },
"designation":"Associate Professor"
}'
Tips
- Always include
user_id
anduser_name
in responses. - Regular flows ignore nested
user
data; admin flows apply them first. - Adjust serializers if you introduce new roles or nested updates.
Deployment & Configuration
This section covers installing project dependencies, managing environment variables, customizing production settings, and deploying the student_course_mgmt Django application via WSGI or ASGI servers.
Installing Dependencies
Use requirements.txt to install pinned packages:
# Create virtual environment
python3 -m venv venv
source venv/bin/activate
# Install dependencies
pip install --upgrade pip
pip install -r requirements.txt
Setting Environment Variables
Store sensitive or environment-specific values outside version control. Create a .env
file at project root:
# .env
SECRET_KEY=your-production-secret-key
DEBUG=False
ALLOWED_HOSTS=your.domain.com,api.your.domain.com
DATABASE_URL=postgres://USER:PASSWORD@HOST:PORT/DB_NAME
JWT_ACCESS_TOKEN_LIFETIME=3600
Load these in settings.py
using os.environ
:
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = os.environ['SECRET_KEY']
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')
import dj_database_url
DATABASES = {
'default': dj_database_url.parse(os.environ.get('DATABASE_URL'))
}
Install dj-database-url
if using DATABASE_URL
:
pip install dj-database-url
Configuring Production Settings
Static Files
Serve static assets with WhiteNoise. Insettings.py
:MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware') STATIC_ROOT = BASE_DIR / 'staticfiles' STATIC_URL = '/static/'
Collect static files before deploy:
python manage.py collectstatic --noinput
Security Headers
SECURE_SSL_REDIRECT = True SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True
JWT Configuration
Override lifetimes via env:from datetime import timedelta SIMPLE_JWT = { 'ACCESS_TOKEN_LIFETIME': timedelta(seconds=int(os.environ.get('JWT_ACCESS_TOKEN_LIFETIME', 300))), # other JWT settings... }
WSGI Deployment
Use Gunicorn to serve the WSGI application defined in student_course_mgmt/wsgi.py
:
# Bind to port 8000, use 4 worker processes
gunicorn student_course_mgmt.wsgi:application \
--bind 0.0.0.0:8000 \
--workers 4 \
--log-level info
Recommended systemd unit (/etc/systemd/system/student_mgmt.service
):
[Unit]
Description=Gunicorn instance for student_course_mgmt
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/project
EnvironmentFile=/path/to/project/.env
ExecStart=/path/to/venv/bin/gunicorn \
--workers 4 \
--bind unix:/run/student_mgmt.sock \
student_course_mgmt.wsgi:application
[Install]
WantedBy=multi-user.target
ASGI Deployment
For asynchronous features, deploy via Daphne or Uvicorn using student_course_mgmt/asgi.py
:
# Using Daphne
daphne -b 0.0.0.0 -p 8001 student_course_mgmt.asgi:application
# Or Uvicorn with auto-reload disabled
uvicorn student_course_mgmt.asgi:application \
--host 0.0.0.0 \
--port 8001 \
--workers 2
Configure systemd similarly, replacing the ExecStart command.
With these steps, you deploy a secure, configurable Django application ready for production.
Contributing & Extending
This section guides you through setting up a local development workflow, running and writing tests, adding new apps or roles, customizing the Django admin, and automating workflows with signals.
1. Local Development Workflow
Clone the repository and create a virtual environment
git clone https://github.com/MrRoy2246/Student-Management.git cd Student-Management python3 -m venv venv source venv/bin/activate
Install dependencies and configure environment
pip install -r requirements.txt cp .env.example .env # Edit .env with database credentials and SECRET_KEY
Apply migrations and create a superuser
python manage.py migrate python manage.py createsuperuser
Run the development server
python manage.py runserver
2. Running Tests
Execute the full test suite with:
python manage.py test
You can run tests for a specific app:
python manage.py test accounts
3. Writing Tests
Each app includes a tests.py template. Follow these patterns:
accounts/tests.py (DRF APIClient)
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
class AccountTests(APITestCase):
def test_user_registration_and_login(self):
url = reverse('accounts:register')
data = {'username': 'jane', 'password': 'strongpass'}
response = self.client.post(url, data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
login_url = reverse('accounts:login')
response = self.client.post(login_url, data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn('token', response.data)
courses/tests.py (Unit test template)
from django.test import TestCase
from .models import Course
class CourseModelTest(TestCase):
def test_course_creation(self):
course = Course.objects.create(name='Math 101', code='MTH101')
self.assertEqual(str(course), 'Math 101 (MTH101)')
Copy this structure into departments/tests.py
, students/tests.py
, and teachers/tests.py
to validate models and APIs.
4. Adding New Apps or Roles
Create the app and add to INSTALLED_APPS in settings.py:
python manage.py startapp clubs
# settings.py INSTALLED_APPS += ['clubs']
Define models and run migrations:
python manage.py makemigrations clubs python manage.py migrate
Register models in admin and write tests:
# clubs/admin.py from django.contrib import admin from .models import Club @admin.register(Club) class ClubAdmin(admin.ModelAdmin): list_display = ('name', 'created_at') search_fields = ('name',)
If introducing a new user role, extend the User model or add a profile model, then hook it via signals (see next section).
5. Customizing Django Admin
accounts/admin.py
Uncomment and extend to modify user fields:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User
@admin.register(User)
class CustomUserAdmin(UserAdmin):
list_display = ('username', 'email', 'role', 'is_active')
list_filter = ('role', 'is_staff', 'is_active')
fieldsets = (
(None, {'fields': ('username', 'password')}),
('Personal info', {'fields': ('first_name', 'last_name', 'email')}),
('Permissions', {'fields': ('role', 'is_active', 'is_staff')}),
)
courses/admin.py
Uncomment registrations and customize:
from django.contrib import admin
from .models import Course, Section
@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
list_display = ('name', 'code', 'department')
search_fields = ('name', 'code')
@admin.register(Section)
class SectionAdmin(admin.ModelAdmin):
list_display = ('course', 'semester', 'instructor')
list_filter = ('semester',)
departments/admin.py, students/admin.py, teachers/admin.py
These already register models. Extend list_display, search_fields, and filters to surface critical data.
6. Signal-Based Automation
students/signals.py
Automatically generate a student_id
:
import uuid
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth import get_user_model
from .models import StudentProfile
User = get_user_model()
def generate_student_id():
return str(uuid.uuid4()).split('-')[0].upper()
@receiver(post_save, sender=User)
def create_student_profile(sender, instance, created, **kwargs):
if created and instance.role == 'student':
StudentProfile.objects.create(user=instance, student_id=generate_student_id())
teachers/signals.py
Automatically create TeacherProfile
with teacher_id
:
import uuid
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth import get_user_model
from .models import TeacherProfile
User = get_user_model()
def generate_teacher_id():
return f"TCHR-{uuid.uuid4().hex[:6].upper()}"
@receiver(post_save, sender=User)
def create_teacher_profile(sender, instance, created, **kwargs):
if created and instance.role == 'teacher':
TeacherProfile.objects.create(user=instance, teacher_id=generate_teacher_id())
Hooking Signals
Ensure your app’s apps.py
imports the signals on ready():
# students/apps.py
from django.apps import AppConfig
class StudentsConfig(AppConfig):
name = 'students'
def ready(self):
import students.signals
Repeat for teachers/apps.py
.
By following these guidelines, you can set up your local environment, ensure code quality through tests, extend the project with new features, customize the admin interface, and automate user workflows with Django signals.