This commit is contained in:
sankalp committed 2025-03-26 01:59:23 +05:45
1 parent 4d8e662fb5
commit 5e572ef062
15 files changed
+1445 -137

No files matched your search

+92 -12
View File
@@ -15,6 +15,7 @@ from app.models import (
Student_Leave,
StudentFeedback,
CourseTracking,
InstituteFeedback,
)
from django.forms import ModelForm
from django.contrib.auth.models import User, Group
@@ -29,6 +30,7 @@ class CustomAdminSite(admin.AdminSite):
app_list = super().get_app_list(request)
model_map = {
# Authentication Models
"User": {
"group": "Authentication",
"group_label": "authentication",
@@ -37,22 +39,66 @@ class CustomAdminSite(admin.AdminSite):
"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"},
# Organization Models
"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",
},
# Human Management Models
"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",
},
"InstituteFeedback": {
"group": "Human Management",
"group_label": "human_management",
},
}
grouped_app_list = [{"name": "Main", "app_label": "dashboard", "models": []}]
@@ -378,6 +424,40 @@ class CourseTrackingAdmin(admin.ModelAdmin):
js = ("js/course_tracking_admin.js",)
@admin.register(InstituteFeedback, site=custom_admin_site)
class InstituteFeedbackAdmin(admin.ModelAdmin):
list_display = ('display_name', 'institute', 'feedback_type', 'rating', 'is_anonymous', 'is_public', 'created_at')
list_filter = ('feedback_type', 'rating', 'is_anonymous', 'is_public', 'created_at', 'institute')
search_fields = ('user__name', 'institute__name', 'feedback_text')
readonly_fields = ('created_at', 'updated_at')
date_hierarchy = 'created_at'
def display_name(self, obj):
return obj.display_name
display_name.short_description = 'Student Name'
fieldsets = (
('Feedback Information', {
'fields': ('institute', 'user', 'feedback_type', 'rating', 'feedback_text')
}),
('Privacy Settings', {
'fields': ('is_anonymous', 'is_public'),
'classes': ('collapse',)
}),
('Timestamps', {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def get_queryset(self, request):
return super().get_queryset(request).select_related('user', 'institute')
class Media:
css = {
'all': ('admin/css/forms.css',)
}
js = ('admin/js/collapse.js',)
custom_admin_site.register(User, UserAdmin)
@@ -0,0 +1,21 @@
# Generated by Django 5.1.7 on 2025-03-25 19:41
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('app', '0004_alter_studentfeedback_options_and_more'),
]
operations = [
migrations.AlterUniqueTogether(
name='studentfeedback',
unique_together={('student', 'teacher')},
),
migrations.RemoveField(
model_name='studentfeedback',
name='subject',
),
]
+35
View File
@@ -0,0 +1,35 @@
# Generated by Django 5.1.7 on 2025-03-25 19:44
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0005_alter_studentfeedback_unique_together_and_more'),
]
operations = [
migrations.CreateModel(
name='InstituteFeedback',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('feedback_type', models.CharField(choices=[('General', 'General'), ('Facilities', 'Facilities'), ('Teaching', 'Teaching'), ('Infrastructure', 'Infrastructure'), ('Administration', 'Administration')], default='General', max_length=20)),
('rating', models.IntegerField(choices=[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)])),
('feedback_text', models.TextField()),
('is_anonymous', models.BooleanField(default=False)),
('is_public', models.BooleanField(default=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('institute', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='feedbacks', to='app.institute')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='institute_feedbacks', to='app.student')),
],
options={
'verbose_name': 'Institute Feedback',
'verbose_name_plural': 'Institute Feedbacks',
'ordering': ['-created_at'],
'unique_together': {('user', 'institute', 'feedback_type')},
},
),
]
@@ -0,0 +1,23 @@
# Generated by Django 5.1.7 on 2025-03-25 20:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0006_institutefeedback'),
]
operations = [
migrations.AddField(
model_name='student',
name='is_superuser',
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name='student',
name='is_active',
field=models.BooleanField(default=True),
),
]
+48 -3
View File
@@ -76,6 +76,11 @@ class Student(AbstractUser):
username = None
email = None
# Add these fields
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=True) # This ensures admin access
is_superuser = models.BooleanField(default=False)
user_permissions = models.ManyToManyField(
"auth.Permission",
verbose_name="user permissions",
@@ -130,6 +135,11 @@ class Student(AbstractUser):
"""Check if student has any groups (permissions)"""
return self.groups.exists()
@property
def is_authenticated(self):
"""Required by Django's authentication system"""
return True
def has_perm(self, perm, obj=None):
"""Check if student has a specific permission"""
if not self.is_active:
@@ -431,7 +441,6 @@ class Student_Leave(models.Model):
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()
@@ -439,13 +448,49 @@ class StudentFeedback(models.Model):
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.student.name} - {self.subject.name} - {self.teacher.name}"
return f"{self.student.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
unique_together = ['student', 'teacher'] # Updated unique constraint
class InstituteFeedback(models.Model):
FEEDBACK_TYPE_CHOICES = (
('General', 'General'),
('Facilities', 'Facilities'),
('Teaching', 'Teaching'),
('Infrastructure', 'Infrastructure'),
('Administration', 'Administration'),
)
institute = models.ForeignKey(Institute, on_delete=models.CASCADE, related_name='feedbacks')
user = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='institute_feedbacks')
feedback_type = models.CharField(max_length=20, choices=FEEDBACK_TYPE_CHOICES, default='General')
rating = models.IntegerField(choices=[(i, i) for i in range(1, 6)]) # 1-5 rating
feedback_text = models.TextField()
is_anonymous = models.BooleanField(default=False)
is_public = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
if self.is_anonymous:
return f"Anonymous - {self.institute.name} - {self.feedback_type}"
return f"{self.user.name} - {self.institute.name} - {self.feedback_type}"
class Meta:
verbose_name = "Institute Feedback"
verbose_name_plural = "Institute Feedbacks"
ordering = ['-created_at']
unique_together = ['user', 'institute', 'feedback_type'] # One feedback per type per user
@property
def display_name(self):
"""Return anonymous if feedback is anonymous, otherwise return user's name"""
return 'Anonymous' if self.is_anonymous else self.user.name
class CourseTracking(models.Model):
+132
View File
@@ -0,0 +1,132 @@
import django.db
from rest_framework import serializers
from .models import (Attendance, AttendanceRecord, Batch, Course, Expenses, FCMDevice, Fee,
Institute, Routine, Salary, Staff, Student, StudentRoutine, Subtopic, Topic, Vendor)
class FCMDeviceSerializer(serializers.ModelSerializer):
class Meta:
model = FCMDevice
fields = ['id', 'token']
depth = 10
class InstituteSerializer(serializers.ModelSerializer):
class Meta:
model = Institute
depth = 10
fields = ['id', 'name', 'phone', 'email', 'address', 'pan_no', 'reg_no', 'logo', 'description']
class SubtopicSerializer(serializers.ModelSerializer):
class Meta:
model = Subtopic
depth = 10
fields = ['id', 'name']
class TopicSerializer(serializers.ModelSerializer):
subtopics = SubtopicSerializer(read_only=True, many=True).data
class Meta:
model = Topic
fields = ['id', 'name', 'subtopics']
depth = 10
class CourseSerializer(serializers.ModelSerializer):
topics = TopicSerializer(read_only=True, many=True).data
class Meta:
model = Course
depth = 3
fields = ['id', 'name', 'amount', 'duration', 'duration_type', 'remarks', 'topics']
class StudentSerializer(serializers.ModelSerializer):
class Meta:
model = Student
depth = 10
fields = [
'id', 'name', 'status', 'gender', 'birth_date', 'email', 'phone',
'temporary_address', 'permanent_address', 'marital_status', 'parent_name',
'parent_phone', 'citizenship_no', 'qualification', 'image', 'batches', 'courses',
'subtotal', 'discount', 'total', 'paid', 'remaining', 'joining_date', 'file', 'remarks'
]
class BatchSerializer(serializers.ModelSerializer):
students = StudentSerializer(many=True).data
class Meta:
model = Batch
depth = 10
fields = ['id', 'name', 'start_date', 'end_date', 'students']
class FeeSerializer(serializers.ModelSerializer):
class Meta:
model = Fee
fields = [
'id', 'student', 'old_total', 'old_paid', 'old_remaining', 'balance_amount',
'payment_date', 'payment_method', 'total', 'paid', 'remaining', 'remarks'
]
depth = 10
class VendorSerializer(serializers.ModelSerializer):
class Meta:
model = Vendor
depth = 10
fields = ['id', 'name', 'address', 'phone']
class ExpensesSerializer(serializers.ModelSerializer):
class Meta:
model = Expenses
depth = 10
fields = [
'id', 'name', 'amount', 'date', 'vendor', 'paid', 'credit', 'credit_date', 'remarks'
]
class SalarySerializer(serializers.ModelSerializer):
class Meta:
model = Salary
depth = 10
fields = '__all__'
class StaffSerializer(serializers.ModelSerializer):
salaries = SalarySerializer(many=True).data
class Meta:
model = Staff
depth = 10
fields = '__all__'
# fields = [
# 'id', 'name', 'gender', 'designation', 'birth_date', 'phone', 'email',
# 'temporary_address', 'permanent_address', 'marital_status', 'parent_name',
# 'parent_phone', 'citizenship_no', 'passport', 'image', 'monthly', 'pending_salary', 'remarks', 'salaries'
# ]
class RoutineSerializer(serializers.ModelSerializer):
class Meta:
model = Routine
depth = 10
fields = ['id', 'name', 'start_time', 'end_time', 'teacher']
class StudentRoutineSerializer(serializers.ModelSerializer):
class Meta:
model = StudentRoutine
depth = 10
fields = ['id', 'student', 'routine', 'course', 'course_status']
class AttendanceRecordSerializer(serializers.ModelSerializer):
class Meta:
model = AttendanceRecord
depth = 10
fields = ['id', 'attendance', 'student', 'student_attend']
class AttendanceSerializer(serializers.ModelSerializer):
records = AttendanceRecordSerializer(many=True).data
class Meta:
model = Attendance
depth = 1
fields = ['id', 'date', 'routine', 'teacher', 'teacher_attend', 'class_status', 'records']
View File
Whitespace-only changes.
+11
View File
@@ -0,0 +1,11 @@
from django import template
register = template.Library()
@register.filter
def get_range(value):
"""
Returns a range of numbers from 0 to value-1
Used for creating star ratings
"""
return range(value)
+8
View File
@@ -0,0 +1,8 @@
from django.urls import path
from app import views
urlpatterns = [
path('dashboard/', views.dashboard, name='dashboard'),
path('student-dashboard/', views.studentDashboard, name='studentDashboard'),
path('teacher-dashboard/', views.teacherDashboard, name='teacherDashboard'),
]
+330 -8
View File
@@ -1,6 +1,19 @@
from app.models import FCMDevice
from django.shortcuts import render
from django.shortcuts import render, redirect, get_object_or_404
from django.http import JsonResponse, HttpResponse
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.db.models import Count, Q, Avg
from django.utils import timezone
from datetime import timedelta
from .models import (
Student, Course, CourseTracking,
Student_Leave, Staff_leave,
Attendance, AttendanceRecord,
StudentFeedback, Routine, StudentRoutine,
Staff
)
from app.admin import custom_admin_site
# Create your views here.
@@ -19,13 +32,13 @@ def showFirebaseJS(request):
importScripts('https://www.gstatic.com/firebasejs/11.0.2/firebase-messaging-compat.js');
firebase.initializeApp({
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
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();
@@ -42,3 +55,312 @@ def showFirebaseJS(request):
});
"""
return HttpResponse(data, content_type="text/javascript")
@login_required
def dashboard(request):
user = request.user
user_groups = user.groups.values_list('name', flat=True)
if 'Student' in user_groups:
return redirect('studentDashboard')
elif 'Teacher' in user_groups:
return redirect('teacherDashboard')
# Get current date and date ranges
today = timezone.now().date()
last_week = today - timedelta(days=7)
last_month = today - timedelta(days=30)
# Student Statistics
total_students = Student.objects.count()
active_students = Student.objects.filter(status='Active').count()
completed_students = Student.objects.filter(status='Completed').count()
on_leave_students = Student.objects.filter(status='Leave').count()
# Course Statistics
total_courses = Course.objects.count()
active_courses = Course.objects.filter(student_trackings__progress_status='In Progress').distinct().count()
completed_courses = Course.objects.filter(student_trackings__progress_status='Completed').distinct().count()
# Course Tracking Statistics
course_trackings = CourseTracking.objects.all()
in_progress_trackings = course_trackings.filter(progress_status='In Progress')
completed_trackings = course_trackings.filter(progress_status='Completed')
dropped_trackings = course_trackings.filter(progress_status='Dropped')
# Recent Leave Requests
recent_student_leaves = Student_Leave.objects.filter(
created_at__gte=last_week
).order_by('-created_at')[:5]
recent_staff_leaves = Staff_leave.objects.filter(
created_at__gte=last_week
).order_by('-created_at')[:5]
# Attendance Statistics
today_attendance = Attendance.objects.filter(date=today).count()
today_present = AttendanceRecord.objects.filter(
attendance__date=today,
student_attend=True
).count()
# Recent Feedback
recent_feedback = StudentFeedback.objects.order_by('-created_at')[:5]
# Course Progress Overview
course_progress = []
for course in Course.objects.all():
trackings = course.student_trackings.all()
if trackings.exists():
avg_progress = trackings.aggregate(avg_progress=Avg('completion_percentage'))['avg_progress']
course_progress.append({
'course': course,
'total_students': trackings.count(),
'in_progress': trackings.filter(progress_status='In Progress').count(),
'completed': trackings.filter(progress_status='Completed').count(),
'average_progress': round(avg_progress, 1) if avg_progress else 0
})
# Monthly Statistics
monthly_stats = {
'new_students': Student.objects.filter(joining_date__gte=last_month).count(),
'completed_courses': completed_trackings.filter(actual_end_date__gte=last_month).count(),
'attendance_rate': round(
(AttendanceRecord.objects.filter(
attendance__date__gte=last_month,
student_attend=True
).count() /
AttendanceRecord.objects.filter(
attendance__date__gte=last_month
).count() * 100) if AttendanceRecord.objects.filter(
attendance__date__gte=last_month
).exists() else 0,
1
)
}
context = {
**custom_admin_site.each_context(request), # This adds the admin context, including the sidebar.
# Student Statistics
'total_students': total_students,
'active_students': active_students,
'completed_students': completed_students,
'on_leave_students': on_leave_students,
# Course Statistics
'total_courses': total_courses,
'active_courses': active_courses,
'completed_courses': completed_courses,
# Course Tracking Statistics
'in_progress_trackings': in_progress_trackings.count(),
'completed_trackings': completed_trackings.count(),
'dropped_trackings': dropped_trackings.count(),
# Leave Requests
'recent_student_leaves': recent_student_leaves,
'recent_staff_leaves': recent_staff_leaves,
# Attendance Statistics
'today_attendance': today_attendance,
'today_present': today_present,
'attendance_rate': round(
(today_present / today_attendance * 100) if today_attendance > 0 else 0,
1
),
# Recent Feedback
'recent_feedback': recent_feedback,
# Course Progress
'course_progress': course_progress,
# Monthly Statistics
'monthly_stats': monthly_stats,
}
return render(request, 'dashboard.html', context)
@login_required
def studentDashboard(request):
"""View to display the student dashboard with their personal information and progress"""
student = request.user
today = timezone.now().date()
last_week = today - timedelta(days=7)
last_month = today - timedelta(days=30)
# Course Progress
course_trackings = CourseTracking.objects.filter(student=student)
total_courses = course_trackings.count()
completed_courses = course_trackings.filter(progress_status='Completed').count()
in_progress_courses = course_trackings.filter(progress_status='In Progress').count()
completion_percentage = (completed_courses / total_courses * 100) if total_courses > 0 else 0
# Course Details
course_details = {}
for tracking in course_trackings:
course_details[tracking.course.name] = {
'start_date': tracking.start_date,
'end_date': tracking.end_date,
'completion_percentage': tracking.completion_percentage,
'progress_status': tracking.progress_status,
'book': tracking.course.book if hasattr(tracking.course, 'book') else None,
'topics': [] # This will be populated if you have topic tracking
}
# Attendance Statistics
attendance_records = AttendanceRecord.objects.filter(student=student)
total_classes = attendance_records.count()
classes_attended = attendance_records.filter(student_attend=True).count()
attendance_percentage = (classes_attended / total_classes * 100) if total_classes > 0 else 0
# Calculate attendance streaks
current_streak = 0
longest_streak = 0
temp_streak = 0
for record in attendance_records.order_by('-attendance__date'):
if record.student_attend:
temp_streak += 1
if temp_streak > longest_streak:
longest_streak = temp_streak
if record.attendance.date >= last_week:
current_streak = temp_streak
else:
temp_streak = 0
# Recent Leave Requests
recent_leaves = Student_Leave.objects.filter(
student=student
).order_by('-created_at')[:5]
# Recent Feedback
recent_feedback = StudentFeedback.objects.filter(
student=student
).order_by('-created_at')[:5]
context = {
**custom_admin_site.each_context(request), # This adds the admin context, including the sidebar.
'student': student,
'title': 'Student Dashboard',
# Course Summary
'course_summary': {
'total_courses': total_courses,
'completed_courses': completed_courses,
'ongoing_courses': in_progress_courses,
'completion_percentage': completion_percentage,
'details': course_details
},
# Attendance Summary
'attendance_summary': {
'total_classes': total_classes,
'classes_attended': classes_attended,
'attendance_percentage': attendance_percentage,
'current_streak': current_streak,
'longest_streak': longest_streak
},
# Recent Activity
'recent_leaves': recent_leaves,
'recent_feedback': recent_feedback,
}
return render(request, 'student_dashboard.html', context)
@login_required
def teacherDashboard(request):
"""View to display the teacher dashboard with their classes and student information"""
teacher = Staff.objects.get(phone=request.user.phone) # Get the Staff object
today = timezone.now().date()
current_time = timezone.now().time()
# Get today's routines through attendance
today_routines = Routine.objects.filter(
teacher=teacher,
attendances__date=today
).order_by('start_time')
# Process routines to include status and attendance
processed_routines = []
for routine in today_routines:
attendance = routine.attendances.filter(date=today).first()
total_students = StudentRoutine.objects.filter(routine=routine).count()
attendance_count = 0 if not attendance else AttendanceRecord.objects.filter(
attendance=attendance,
student_attend=True
).count()
processed_routines.append({
'name': routine.name,
'start_time': routine.start_time,
'end_time': routine.end_time,
'is_completed': routine.end_time < current_time,
'is_ongoing': routine.start_time <= current_time <= routine.end_time,
'total_students': total_students,
'attendance_count': attendance_count
})
# Calculate class statistics
total_classes = today_routines.count()
completed_classes = len([r for r in processed_routines if r['is_completed']])
# Get student statistics
total_students = StudentRoutine.objects.filter(
routine__teacher=teacher
).values('student').distinct().count()
# Calculate present students for today
present_students = AttendanceRecord.objects.filter(
attendance__routine__teacher=teacher,
attendance__date=today,
student_attend=True
).count()
# Get teacher's feedback statistics
feedback = StudentFeedback.objects.filter(teacher=teacher)
avg_rating = feedback.aggregate(Avg('rating'))['rating__avg'] or 0
avg_rating_rounded = int(avg_rating)
remaining_stars = 5 - avg_rating_rounded
# Get leave statistics
leaves = Staff_leave.objects.filter(staff=teacher)
pending_leaves = leaves.filter(status=0).count()
approved_leaves = leaves.filter(status=1).count()
rejected_leaves = leaves.filter(status=2).count()
# Get recent activity
recent_leaves = leaves.order_by('-created_at')[:5]
recent_feedback = feedback.order_by('-created_at')[:5]
context = {
**custom_admin_site.each_context(request), # This adds the admin context, including the sidebar.
'teacher': teacher,
'title': 'Teacher Dashboard',
# Class Statistics
'today_classes': total_classes,
'completed_classes': completed_classes,
'today_routines': processed_routines,
# Student Statistics
'total_students': total_students,
'present_students': present_students,
# Feedback Statistics
'avg_rating': avg_rating,
'avg_rating_rounded': avg_rating_rounded,
'remaining_stars': remaining_stars,
# Leave Statistics
'pending_leaves': pending_leaves,
'approved_leaves': approved_leaves,
'rejected_leaves': rejected_leaves,
# Recent Activity
'recent_leaves': recent_leaves,
'recent_feedback': recent_feedback,
}
return render(request, 'teacher_dashboard.html', context)