892 lines
40 KiB
Python
892 lines
40 KiB
Python
import random
|
|
from datetime import datetime, timedelta
|
|
import pytz
|
|
from django.core.management.base import BaseCommand
|
|
from django.utils import timezone
|
|
from django.contrib.auth.models import Group
|
|
from django.db import transaction
|
|
from faker import Faker
|
|
from app.models import (
|
|
Institute, Batch, Course, Subject, Staff, Student, Parent,
|
|
Routine, Attendance, AttendanceRecord, Notice,
|
|
StaffLeave, StudentLeave, StudentFeedback, ParentFeedback,
|
|
InstituteFeedback, StaffInstituteFeedback, ParentInstituteFeedback,
|
|
CourseTracking, TeacherParentMeeting, SubjectFile
|
|
)
|
|
|
|
# Nepali-specific data
|
|
NEPALI_FIRST_NAMES = [
|
|
'Aarav', 'Aayush', 'Abhishek', 'Aditya', 'Amit', 'Anish', 'Anup', 'Arjun', 'Ashish', 'Bibek',
|
|
'Bikash', 'Bimal', 'Bishal', 'Bishnu', 'Buddha', 'Chandra', 'Dawa', 'Deepak', 'Dinesh', 'Dipesh',
|
|
'Ganesh', 'Gaurav', 'Gopal', 'Hari', 'Hemant', 'Jeevan', 'Karan', 'Krishna', 'Kumar', 'Laxman',
|
|
'Madan', 'Manoj', 'Nabin', 'Narayan', 'Niraj', 'Nishan', 'Prabin', 'Prakash', 'Pramod', 'Prasad',
|
|
'Pratik', 'Pratikshya', 'Rabin', 'Raj', 'Rajesh', 'Rakesh', 'Ram', 'Ramesh', 'Ravi', 'Rohit',
|
|
'Roshan', 'Sagar', 'Sajan', 'Sandeep', 'Sanjay', 'Santosh', 'Saroj', 'Saurav', 'Shankar', 'Shiva',
|
|
'Siddhartha', 'Suman', 'Suresh', 'Sushil', 'Umesh', 'Uttam', 'Vijay', 'Vikash', 'Vishal', 'Yogesh'
|
|
]
|
|
|
|
NEPALI_LAST_NAMES = [
|
|
'Acharya', 'Adhikari', 'Aryal', 'Bajracharya', 'Bhandari', 'Bhattarai', 'Chaudhary', 'Dahal', 'Dangol',
|
|
'Dhakal', 'Gautam', 'Ghimire', 'Gurung', 'Joshi', 'Kafle', 'Karki', 'Khadka', 'Khanal', 'Lama',
|
|
'Limbu', 'Maharjan', 'Malla', 'Neupane', 'Pandey', 'Panta', 'Poudel', 'Rai', 'Rana', 'Regmi',
|
|
'Sharma', 'Shrestha', 'Silwal', 'Singh', 'Tamang', 'Thapa', 'Timalsina', 'Tuladhar', 'Upadhyaya'
|
|
]
|
|
|
|
NEPALI_DESIGNATIONS = [
|
|
'Teacher',
|
|
'Principal',
|
|
'HOD',
|
|
'Admission Officer',
|
|
'Staff'
|
|
]
|
|
|
|
NEPALI_CITIES = [
|
|
'Kathmandu', 'Pokhara', 'Lalitpur', 'Bhaktapur', 'Biratnagar', 'Birgunj', 'Dharan', 'Bharatpur',
|
|
'Butwal', 'Hetauda', 'Dhangadhi', 'Nepalgunj', 'Itahari', 'Damak', 'Siddharthanagar'
|
|
]
|
|
|
|
class Command(BaseCommand):
|
|
help = 'Generate fake data for testing the SMS application'
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument('--students', type=int, default=50, help='Number of students to create')
|
|
parser.add_argument('--staff', type=int, default=20, help='Number of staff members to create')
|
|
parser.add_argument('--parents', type=int, default=40, help='Number of parents to create')
|
|
parser.add_argument('--courses', type=int, default=5, help='Number of courses to create')
|
|
parser.add_argument('--subjects', type=int, default=4, help='Subjects per course')
|
|
parser.add_argument('--clear', action='store_true', help='Clear existing data before generating new data')
|
|
|
|
@transaction.atomic
|
|
def handle(self, *args, **options):
|
|
fake = Faker()
|
|
|
|
# Get parameters
|
|
num_students = max(10, options['students']) # Ensure minimum of 10 students
|
|
num_staff = max(5, options['staff']) # Ensure minimum of 5 staff
|
|
num_parents = max(8, options['parents']) # Ensure minimum of 8 parents
|
|
num_courses = max(3, options['courses']) # Ensure minimum of 3 courses
|
|
subjects_per_course = max(3, options['subjects']) # Ensure minimum of 3 subjects per course
|
|
clear_data = options['clear']
|
|
|
|
# Get or create groups
|
|
staff_group, _ = Group.objects.get_or_create(name='Teacher')
|
|
parent_group, _ = Group.objects.get_or_create(name='Parent')
|
|
student_group, _ = Group.objects.get_or_create(name='Student')
|
|
|
|
# Clear existing data if requested
|
|
if clear_data:
|
|
self.stdout.write(self.style.WARNING('Clearing existing data...'))
|
|
TeacherParentMeeting.objects.all().delete()
|
|
ParentInstituteFeedback.objects.all().delete()
|
|
StaffInstituteFeedback.objects.all().delete()
|
|
InstituteFeedback.objects.all().delete()
|
|
ParentFeedback.objects.all().delete()
|
|
StudentFeedback.objects.all().delete()
|
|
StudentLeave.objects.all().delete()
|
|
StaffLeave.objects.all().delete()
|
|
Notice.objects.all().delete()
|
|
AttendanceRecord.objects.all().delete()
|
|
Attendance.objects.all().delete()
|
|
Routine.objects.all().delete()
|
|
SubjectFile.objects.all().delete()
|
|
CourseTracking.objects.all().delete()
|
|
|
|
# Clear many-to-many relationships before deleting models
|
|
for parent in Parent.objects.all():
|
|
parent.students.clear()
|
|
|
|
for student in Student.objects.all():
|
|
student.batches.clear()
|
|
|
|
Subject.objects.all().delete()
|
|
Parent.objects.all().delete()
|
|
Student.objects.all().delete()
|
|
Staff.objects.all().delete()
|
|
Course.objects.all().delete()
|
|
Batch.objects.all().delete()
|
|
Institute.objects.all().delete()
|
|
|
|
self.stdout.write(self.style.SUCCESS('Data cleared successfully'))
|
|
|
|
# Create Institute
|
|
institute = self._create_institute(fake)
|
|
|
|
# Create batches (last 4 years)
|
|
batches = self._create_batches()
|
|
|
|
# Create courses
|
|
courses = self._create_courses(fake, num_courses)
|
|
|
|
# Create subjects for each course
|
|
subjects = self._create_subjects(fake, courses, subjects_per_course)
|
|
|
|
# Create staff members
|
|
staff_members = self._create_staff(fake, num_staff, staff_group)
|
|
|
|
# Create students
|
|
students = self._create_students(fake, num_students, courses, batches, student_group)
|
|
|
|
# Create parents and link to students
|
|
parents = self._create_parents(fake, num_parents, students, parent_group)
|
|
|
|
# Create routines and class schedules
|
|
routines = self._create_routines(courses, subjects, staff_members)
|
|
|
|
# Create attendance records
|
|
attendance_records = self._create_attendance(routines, students)
|
|
|
|
# Create notices
|
|
notices = self._create_notices(fake)
|
|
|
|
# Create leave requests
|
|
self._create_leaves(fake, staff_members, students)
|
|
|
|
# Create feedback
|
|
self._create_feedback(fake, students, staff_members, parents, institute)
|
|
|
|
# Create parent-teacher meetings
|
|
self._create_meetings(fake, staff_members, parents)
|
|
|
|
# Create subject files
|
|
self._create_subject_files(fake, subjects, staff_members)
|
|
|
|
# Create course tracking for students
|
|
self._create_course_tracking(students, courses)
|
|
|
|
self.stdout.write(self.style.SUCCESS('Successfully generated fake data!'))
|
|
|
|
def _get_nepali_name(self):
|
|
return f"{random.choice(NEPALI_FIRST_NAMES)} {random.choice(NEPALI_LAST_NAMES)}"
|
|
|
|
def _get_nepali_phone(self):
|
|
return f"98{random.randint(1000000, 9999999)}"
|
|
|
|
def _get_nepali_address(self, city):
|
|
wards = [f"Ward No. {random.randint(1, 35)}" for _ in range(3)]
|
|
return f"{random.choice(wards)}, {city}, Nepal"
|
|
|
|
def _create_institute(self, fake):
|
|
city = random.choice(NEPALI_CITIES)
|
|
institute, created = Institute.objects.get_or_create(
|
|
name=f"{city} Educational Institute",
|
|
defaults={
|
|
'phone': self._get_nepali_phone(),
|
|
'email': fake.company_email(),
|
|
'address': self._get_nepali_address(city),
|
|
'pan_no': f"PAN{random.randint(100000, 999999)}",
|
|
'reg_no': f"REG{random.randint(100000, 999999)}",
|
|
'description': fake.paragraph(nb_sentences=3)
|
|
}
|
|
)
|
|
if created:
|
|
self.stdout.write(self.style.SUCCESS(f'Created institute: {institute.name}'))
|
|
return institute
|
|
|
|
def _create_batches(self):
|
|
batches = []
|
|
current_year = datetime.now().year
|
|
|
|
for year in range(current_year - 3, current_year + 1):
|
|
batch, created = Batch.objects.get_or_create(
|
|
name=f'Batch {year}',
|
|
defaults={'year': datetime(year, 1, 1)}
|
|
)
|
|
batches.append(batch)
|
|
if created:
|
|
self.stdout.write(self.style.SUCCESS(f'Created batch: {batch.name}'))
|
|
|
|
return batches
|
|
|
|
def _create_courses(self, fake, num_courses):
|
|
courses = []
|
|
course_names = [
|
|
'Computer Science Engineering',
|
|
'Electrical Engineering',
|
|
'Mechanical Engineering',
|
|
'Civil Engineering',
|
|
'Chemical Engineering',
|
|
'Electronics Engineering',
|
|
'Information Technology',
|
|
'Aerospace Engineering',
|
|
'Biotechnology Engineering',
|
|
'Data Science'
|
|
]
|
|
|
|
# Ensure we don't try to create more courses than we have names for
|
|
num_to_create = min(num_courses, len(course_names))
|
|
|
|
for i in range(num_to_create):
|
|
duration = random.choice([3, 4])
|
|
duration_type = random.choice(['Year', 'Semester'])
|
|
|
|
course, created = Course.objects.get_or_create(
|
|
name=course_names[i],
|
|
defaults={
|
|
'duration': duration,
|
|
'duration_type': duration_type
|
|
}
|
|
)
|
|
courses.append(course)
|
|
if created:
|
|
self.stdout.write(self.style.SUCCESS(f'Created course: {course.name}'))
|
|
|
|
return courses
|
|
|
|
def _create_subjects(self, fake, courses, subjects_per_course):
|
|
subjects = []
|
|
|
|
subject_names = {
|
|
'Computer Science Engineering': [
|
|
'Data Structures', 'Algorithms', 'Database Systems', 'Operating Systems',
|
|
'Computer Networks', 'Software Engineering', 'Web Development', 'AI and Machine Learning',
|
|
'Computer Architecture', 'Compiler Design', 'Computer Graphics', 'Cloud Computing'
|
|
],
|
|
'Electrical Engineering': [
|
|
'Circuit Theory', 'Electrical Machines', 'Power Systems', 'Control Systems',
|
|
'Digital Electronics', 'Microprocessors', 'Power Electronics', 'Electrical Measurements',
|
|
'Renewable Energy', 'Smart Grid', 'High Voltage Engineering', 'Power System Protection'
|
|
],
|
|
'Mechanical Engineering': [
|
|
'Thermodynamics', 'Fluid Mechanics', 'Manufacturing Processes', 'Machine Design',
|
|
'Heat Transfer', 'Engineering Mechanics', 'Automobile Engineering', 'Materials Science',
|
|
'Robotics', 'CAD/CAM', 'Industrial Engineering', 'Refrigeration and Air Conditioning'
|
|
],
|
|
'Information Technology': [
|
|
'Programming Fundamentals', 'Data Structures', 'Database Management', 'Web Technologies',
|
|
'Computer Networks', 'Software Engineering', 'Cybersecurity', 'Cloud Computing',
|
|
'Mobile Application Development', 'Big Data Analytics', 'IoT', 'Blockchain Technology'
|
|
],
|
|
'Data Science': [
|
|
'Statistical Methods', 'Machine Learning', 'Data Mining', 'Big Data Analytics',
|
|
'Data Visualization', 'Deep Learning', 'Natural Language Processing', 'Time Series Analysis',
|
|
'Business Intelligence', 'Predictive Analytics', 'Data Warehousing', 'Data Engineering'
|
|
]
|
|
}
|
|
|
|
# Add generic subjects for courses not explicitly defined
|
|
generic_subjects = [
|
|
'Mathematics I', 'Mathematics II', 'Physics', 'Chemistry',
|
|
'Technical Writing', 'Engineering Ethics', 'Project Management', 'Research Methods',
|
|
'Environmental Science', 'Economics', 'Management', 'Communication Skills'
|
|
]
|
|
|
|
for course in courses:
|
|
# Get subject list for this course or use generic subjects
|
|
if course.name in subject_names:
|
|
course_subject_names = subject_names[course.name]
|
|
else:
|
|
course_subject_names = generic_subjects
|
|
|
|
max_year_or_sem = course.duration
|
|
if course.duration_type == 'Semester':
|
|
max_year_or_sem = course.duration * 2
|
|
|
|
# Create subjects for each year/semester
|
|
for year_or_sem in range(1, max_year_or_sem + 1):
|
|
# Calculate number of subjects for this year/semester
|
|
# Ensure at least 2 subjects per year/semester
|
|
num_subjects = max(2, min(subjects_per_course, len(course_subject_names)))
|
|
|
|
# Select subjects ensuring no duplicates within the same year/semester
|
|
available_subjects = [s for s in course_subject_names if not Subject.objects.filter(
|
|
course=course,
|
|
name=s,
|
|
period_or_year=year_or_sem
|
|
).exists()]
|
|
|
|
if len(available_subjects) < num_subjects:
|
|
# If not enough unique subjects, add some from generic subjects
|
|
available_subjects.extend([
|
|
s for s in generic_subjects
|
|
if s not in available_subjects and not Subject.objects.filter(
|
|
course=course,
|
|
name=s,
|
|
period_or_year=year_or_sem
|
|
).exists()
|
|
])
|
|
|
|
selected_subjects = random.sample(available_subjects, min(num_subjects, len(available_subjects)))
|
|
|
|
for subject_name in selected_subjects:
|
|
subject, created = Subject.objects.get_or_create(
|
|
name=subject_name,
|
|
course=course,
|
|
period_or_year=year_or_sem
|
|
)
|
|
subjects.append(subject)
|
|
if created:
|
|
self.stdout.write(self.style.SUCCESS(f'Created subject: {subject.name} for {course.name} in {year_or_sem}'))
|
|
|
|
return subjects
|
|
|
|
def _create_staff(self, fake, num_staff, staff_group):
|
|
staff_members = []
|
|
|
|
for i in range(num_staff):
|
|
gender = random.choice(['Male', 'Female'])
|
|
name = self._get_nepali_name()
|
|
phone = self._get_nepali_phone()
|
|
city = random.choice(NEPALI_CITIES)
|
|
|
|
staff = Staff(
|
|
name=name,
|
|
phone=phone,
|
|
designation=random.choice(NEPALI_DESIGNATIONS),
|
|
gender=gender,
|
|
birth_date=fake.date_of_birth(minimum_age=30, maximum_age=65),
|
|
email=fake.email(),
|
|
temporary_address=self._get_nepali_address(city),
|
|
permanent_address=self._get_nepali_address(city),
|
|
marital_status=random.choice(['Married', 'Unmarried']),
|
|
parent_name=self._get_nepali_name(),
|
|
parent_phone=self._get_nepali_phone(),
|
|
citizenship_no=f"{random.randint(10000, 99999)}-{random.randint(10000, 99999)}",
|
|
joining_date=fake.date_between(start_date='-5y', end_date='today')
|
|
)
|
|
staff.save()
|
|
staff.set_password('staff123')
|
|
staff.save()
|
|
staff.groups.add(staff_group)
|
|
staff_members.append(staff)
|
|
self.stdout.write(self.style.SUCCESS(f'Created staff: {staff.name}'))
|
|
|
|
return staff_members
|
|
|
|
def _create_students(self, fake, num_students, courses, batches, student_group):
|
|
students = []
|
|
|
|
for i in range(num_students):
|
|
gender = random.choice(['Male', 'Female'])
|
|
name = self._get_nepali_name()
|
|
phone = self._get_nepali_phone()
|
|
city = random.choice(NEPALI_CITIES)
|
|
|
|
course = random.choice(courses)
|
|
max_semester = course.duration
|
|
if course.duration_type == 'Semester':
|
|
max_semester = course.duration * 2
|
|
|
|
current_period = random.randint(1, max_semester)
|
|
|
|
student = Student(
|
|
name=name,
|
|
status=random.choice(['Active', 'Leave', 'Completed']),
|
|
gender=gender,
|
|
birth_date=fake.date_of_birth(minimum_age=18, maximum_age=25),
|
|
email=fake.email(),
|
|
phone=phone,
|
|
temporary_address=self._get_nepali_address(city),
|
|
permanent_address=self._get_nepali_address(city),
|
|
marital_status=random.choice(['Married', 'Unmarried']),
|
|
parent_name=self._get_nepali_name(),
|
|
parent_phone=self._get_nepali_phone(),
|
|
citizenship_no=f"{random.randint(10000, 99999)}-{random.randint(10000, 99999)}",
|
|
course=course,
|
|
current_period=current_period,
|
|
joining_date=fake.date_between(start_date='-4y', end_date='-1y')
|
|
)
|
|
student.save()
|
|
student.set_password('student123')
|
|
student.save()
|
|
student.groups.add(student_group)
|
|
|
|
batch = random.choice(batches)
|
|
student.batches.add(batch)
|
|
|
|
students.append(student)
|
|
self.stdout.write(self.style.SUCCESS(f'Created student: {student.name}'))
|
|
|
|
return students
|
|
|
|
def _create_parents(self, fake, num_parents, students, parent_group):
|
|
parents = []
|
|
|
|
for i in range(num_parents):
|
|
name = self._get_nepali_name()
|
|
phone = self._get_nepali_phone()
|
|
city = random.choice(NEPALI_CITIES)
|
|
|
|
parent = Parent(
|
|
name=name,
|
|
phone=phone,
|
|
email=fake.email(),
|
|
address=self._get_nepali_address(city),
|
|
)
|
|
parent.save()
|
|
parent.set_password('parent123')
|
|
parent.save()
|
|
parent.groups.add(parent_group)
|
|
|
|
num_children = random.randint(1, min(2, len(students)))
|
|
assigned_students = random.sample(students, num_children)
|
|
for student in assigned_students:
|
|
parent.students.add(student)
|
|
|
|
parents.append(parent)
|
|
self.stdout.write(self.style.SUCCESS(f'Created parent: {parent.name} with {num_children} children'))
|
|
|
|
return parents
|
|
|
|
def _create_routines(self, courses, subjects, staff_members):
|
|
routines = []
|
|
days_of_week = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
|
|
time_slots = [
|
|
('09:00', '10:00'),
|
|
('10:15', '11:15'),
|
|
('11:30', '12:30'),
|
|
('13:30', '14:30'),
|
|
('14:45', '15:45'),
|
|
('16:00', '17:00')
|
|
]
|
|
|
|
# Create a schedule for each course and semester
|
|
for course in courses:
|
|
course_subjects = Subject.objects.filter(course=course)
|
|
|
|
# Group subjects by period/year
|
|
subjects_by_period = {}
|
|
for subject in course_subjects:
|
|
if subject.period_or_year not in subjects_by_period:
|
|
subjects_by_period[subject.period_or_year] = []
|
|
subjects_by_period[subject.period_or_year].append(subject)
|
|
|
|
# Create routine for each period/year
|
|
for period, period_subjects in subjects_by_period.items():
|
|
# Assign teachers to subjects
|
|
teacher_subject_assignments = {}
|
|
available_teachers = staff_members.copy()
|
|
|
|
for subject in period_subjects:
|
|
if not available_teachers:
|
|
available_teachers = staff_members.copy()
|
|
|
|
teacher = random.choice(available_teachers)
|
|
teacher_subject_assignments[subject] = teacher
|
|
available_teachers.remove(teacher)
|
|
|
|
# Create routine for each day
|
|
for day in days_of_week:
|
|
# Shuffle time slots for variety
|
|
shuffled_slots = time_slots.copy()
|
|
random.shuffle(shuffled_slots)
|
|
|
|
# Assign subjects to time slots
|
|
for subject, teacher in teacher_subject_assignments.items():
|
|
if not shuffled_slots:
|
|
break
|
|
|
|
start_time_str, end_time_str = shuffled_slots.pop()
|
|
start_time = datetime.strptime(start_time_str, "%H:%M").time()
|
|
end_time = datetime.strptime(end_time_str, "%H:%M").time()
|
|
|
|
# Check for conflicts
|
|
conflicting_routine = Routine.objects.filter(
|
|
teacher=teacher,
|
|
start_time=start_time,
|
|
end_time=end_time
|
|
).first()
|
|
|
|
if not conflicting_routine:
|
|
routine = Routine(
|
|
course=course,
|
|
subject=subject,
|
|
teacher=teacher,
|
|
start_time=start_time,
|
|
end_time=end_time,
|
|
period_or_year=period,
|
|
is_active=True
|
|
)
|
|
|
|
try:
|
|
routine.save()
|
|
routines.append(routine)
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f'Created routine for {subject.name} with {teacher.name} '
|
|
f'on {day} at {start_time_str}-{end_time_str}'
|
|
)
|
|
)
|
|
except Exception as e:
|
|
# Skip if there's an error (likely due to unique constraint violation)
|
|
pass
|
|
|
|
return routines
|
|
|
|
def _create_attendance(self, routines, students):
|
|
attendance_records = []
|
|
|
|
# Create attendance for the past 2 weeks
|
|
for day_offset in range(14, 0, -1):
|
|
date = datetime.now().date() - timedelta(days=day_offset)
|
|
|
|
# Skip weekends
|
|
if date.weekday() >= 5: # 5 and 6 are Saturday and Sunday
|
|
continue
|
|
|
|
for routine in routines:
|
|
# Create attendance for this routine on this date
|
|
attendance = Attendance(
|
|
date=date,
|
|
routine=routine,
|
|
teacher=routine.teacher,
|
|
teacher_attend=random.choices([True, False], weights=[0.95, 0.05])[0], # 95% chance of teacher attendance
|
|
class_status=True
|
|
)
|
|
try:
|
|
attendance.save()
|
|
|
|
# Find students in this course and semester
|
|
course_students = Student.objects.filter(
|
|
course=routine.course,
|
|
current_period=routine.period_or_year
|
|
)
|
|
|
|
# Create attendance records for students
|
|
for student in course_students:
|
|
# Base attendance probability on student's status
|
|
if student.status == 'Active':
|
|
attendance_prob = 0.85 # 85% chance for active students
|
|
elif student.status == 'Leave':
|
|
attendance_prob = 0.30 # 30% chance for students on leave
|
|
else:
|
|
attendance_prob = 0.10 # 10% chance for completed students
|
|
|
|
# Add some randomness to the attendance pattern
|
|
attendance_prob += random.uniform(-0.1, 0.1)
|
|
attendance_prob = max(0, min(1, attendance_prob)) # Ensure between 0 and 1
|
|
|
|
is_present = random.choices([True, False], weights=[attendance_prob, 1-attendance_prob])[0]
|
|
|
|
record = AttendanceRecord(
|
|
attendance=attendance,
|
|
student=student,
|
|
student_attend=is_present
|
|
)
|
|
record.save()
|
|
attendance_records.append(record)
|
|
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f'Created attendance for {routine.subject.name} on {date} '
|
|
f'with {course_students.count()} students'
|
|
)
|
|
)
|
|
except Exception as e:
|
|
# Skip if there's an error
|
|
pass
|
|
|
|
return attendance_records
|
|
|
|
def _create_notices(self, fake):
|
|
notices = []
|
|
|
|
for i in range(10): # Create 10 notices
|
|
notice = Notice(
|
|
title=fake.sentence(),
|
|
message=fake.paragraph(nb_sentences=3),
|
|
created_at=fake.date_time_between(start_date='-30d', end_date='now')
|
|
)
|
|
notice.save()
|
|
notices.append(notice)
|
|
self.stdout.write(self.style.SUCCESS(f'Created notice: {notice.title}'))
|
|
|
|
return notices
|
|
|
|
def _create_leaves(self, fake, staff_members, students):
|
|
# Create staff leaves
|
|
for staff in random.sample(staff_members, len(staff_members) // 3): # 1/3 of staff
|
|
start_date = fake.date_between(start_date='-30d', end_date='+30d')
|
|
end_date = start_date + timedelta(days=random.randint(1, 5))
|
|
|
|
leave = StaffLeave(
|
|
staff=staff,
|
|
start_date=start_date,
|
|
end_date=end_date,
|
|
message=fake.paragraph(),
|
|
status=random.choice([0, 1, 2]) # Pending, Approved, Rejected
|
|
)
|
|
leave.save()
|
|
self.stdout.write(self.style.SUCCESS(f'Created staff leave for {staff.name}'))
|
|
|
|
# Create student leaves
|
|
for student in random.sample(students, len(students) // 3): # 1/3 of students
|
|
start_date = fake.date_between(start_date='-30d', end_date='+30d')
|
|
end_date = start_date + timedelta(days=random.randint(1, 5))
|
|
|
|
leave = StudentLeave(
|
|
student=student,
|
|
start_date=start_date,
|
|
end_date=end_date,
|
|
message=fake.paragraph(),
|
|
status=random.choice([0, 1, 2]) # Pending, Approved, Rejected
|
|
)
|
|
leave.save()
|
|
self.stdout.write(self.style.SUCCESS(f'Created student leave for {student.name}'))
|
|
|
|
def _create_feedback(self, fake, students, staff_members, parents, institute):
|
|
# Create student feedback for teachers
|
|
for student in random.sample(students, len(students) // 2):
|
|
# Each student gives feedback to 2-3 teachers
|
|
num_teachers = random.randint(2, min(3, len(staff_members)))
|
|
selected_teachers = random.sample(staff_members, num_teachers)
|
|
|
|
for teacher in selected_teachers:
|
|
try:
|
|
# Generate more realistic ratings (tend to be positive but with some variation)
|
|
rating = random.choices(
|
|
[3.5, 4.0, 4.5, 5.0],
|
|
weights=[0.1, 0.2, 0.3, 0.4]
|
|
)[0]
|
|
|
|
feedback = StudentFeedback(
|
|
student=student,
|
|
teacher=teacher,
|
|
rating=rating,
|
|
feedback_text=fake.paragraph()
|
|
)
|
|
feedback.save()
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f'Created student feedback from {student.name} for {teacher.name} '
|
|
f'with rating {rating}'
|
|
)
|
|
)
|
|
except:
|
|
# Skip if there's an error (likely due to unique constraint)
|
|
pass
|
|
|
|
# Create parent feedback for teachers
|
|
for parent in random.sample(parents, len(parents) // 2):
|
|
parent_students = parent.students.all()
|
|
if parent_students:
|
|
for student in parent_students:
|
|
# Each parent gives feedback for 1-2 teachers per student
|
|
num_teachers = random.randint(1, min(2, len(staff_members)))
|
|
selected_teachers = random.sample(staff_members, num_teachers)
|
|
|
|
for teacher in selected_teachers:
|
|
try:
|
|
# Parent ratings tend to be slightly higher than student ratings
|
|
rating = random.choices(
|
|
[4.0, 4.5, 5.0],
|
|
weights=[0.2, 0.3, 0.5]
|
|
)[0]
|
|
|
|
feedback = ParentFeedback(
|
|
parent=parent,
|
|
teacher=teacher,
|
|
student=student,
|
|
rating=rating,
|
|
feedback_text=fake.paragraph()
|
|
)
|
|
feedback.save()
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f'Created parent feedback from {parent.name} for {teacher.name} '
|
|
f'regarding {student.name} with rating {rating}'
|
|
)
|
|
)
|
|
except:
|
|
# Skip if there's an error
|
|
pass
|
|
|
|
# Create institute feedback from students
|
|
for student in random.sample(students, len(students) // 3):
|
|
try:
|
|
# Student institute ratings tend to be slightly lower than teacher ratings
|
|
rating = random.choices(
|
|
[3.0, 3.5, 4.0, 4.5, 5.0],
|
|
weights=[0.1, 0.2, 0.3, 0.2, 0.2]
|
|
)[0]
|
|
|
|
feedback = InstituteFeedback(
|
|
institute=institute,
|
|
user=student,
|
|
feedback_type=random.choice(['General', 'Facilities', 'Teaching', 'Infrastructure', 'Administration']),
|
|
rating=rating,
|
|
feedback_text=fake.paragraph(),
|
|
is_anonymous=random.choice([True, False]),
|
|
is_public=True
|
|
)
|
|
feedback.save()
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f'Created institute feedback from {student.name} with rating {rating}'
|
|
)
|
|
)
|
|
except:
|
|
# Skip if there's an error
|
|
pass
|
|
|
|
# Create staff institute feedback
|
|
for staff in random.sample(staff_members, len(staff_members) // 3):
|
|
try:
|
|
# Staff ratings tend to be more balanced
|
|
rating = random.choices(
|
|
[3.0, 3.5, 4.0, 4.5, 5.0],
|
|
weights=[0.15, 0.25, 0.3, 0.2, 0.1]
|
|
)[0]
|
|
|
|
feedback = StaffInstituteFeedback(
|
|
institute=institute,
|
|
staff=staff,
|
|
feedback_type=random.choice(['General', 'Facilities', 'Teaching', 'Infrastructure', 'Administration']),
|
|
rating=rating,
|
|
feedback_text=fake.paragraph(),
|
|
is_anonymous=random.choice([True, False]),
|
|
is_public=True
|
|
)
|
|
feedback.save()
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f'Created staff institute feedback from {staff.name} with rating {rating}'
|
|
)
|
|
)
|
|
except:
|
|
# Skip if there's an error
|
|
pass
|
|
|
|
# Create parent institute feedback
|
|
for parent in random.sample(parents, len(parents) // 3):
|
|
try:
|
|
# Parent institute ratings tend to be higher
|
|
rating = random.choices(
|
|
[3.5, 4.0, 4.5, 5.0],
|
|
weights=[0.1, 0.2, 0.3, 0.4]
|
|
)[0]
|
|
|
|
feedback = ParentInstituteFeedback(
|
|
institute=institute,
|
|
parent=parent,
|
|
feedback_type=random.choice(['General', 'Facilities', 'Administration']),
|
|
rating=rating,
|
|
feedback_text=fake.paragraph(),
|
|
is_anonymous=random.choice([True, False]),
|
|
is_public=True
|
|
)
|
|
feedback.save()
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f'Created parent institute feedback from {parent.name} with rating {rating}'
|
|
)
|
|
)
|
|
except:
|
|
# Skip if there's an error
|
|
pass
|
|
|
|
def _create_meetings(self, fake, staff_members, parents):
|
|
# Create parent-teacher meetings
|
|
future_dates = [datetime.now().date() + timedelta(days=d) for d in range(1, 15)]
|
|
|
|
for staff in random.sample(staff_members, len(staff_members) // 2):
|
|
for parent in random.sample(parents, min(3, len(parents))):
|
|
meeting_date = random.choice(future_dates)
|
|
meeting_hour = random.randint(9, 16)
|
|
meeting_minute = random.choice([0, 15, 30, 45])
|
|
meeting_time = f"{meeting_hour:02d}:{meeting_minute:02d}"
|
|
meeting_status = random.choice(['scheduled', 'rescheduled', 'completed', 'cancelled'])
|
|
|
|
try:
|
|
meeting = TeacherParentMeeting(
|
|
meeting_date=meeting_date,
|
|
meeting_time=datetime.strptime(meeting_time, "%H:%M").time(),
|
|
duration=30,
|
|
status=meeting_status,
|
|
agenda=fake.paragraph(),
|
|
notes=fake.paragraph() if meeting_status == 'completed' else '',
|
|
cancellation_reason=fake.paragraph() if meeting_status == 'cancelled' else '',
|
|
is_online=random.choice([True, False])
|
|
)
|
|
|
|
if meeting.is_online:
|
|
meeting.meeting_link = f"https://meet.example.com/{fake.uuid4()}"
|
|
|
|
meeting.save()
|
|
self.stdout.write(self.style.SUCCESS(f'Created parent-teacher meeting on {meeting_date}'))
|
|
except Exception as e:
|
|
# Skip if there's an error
|
|
pass
|
|
|
|
def _create_subject_files(self, fake, subjects, staff_members):
|
|
# Create subject files (lecture notes, etc.)
|
|
for subject in random.sample(subjects, len(subjects) // 2):
|
|
# Choose a teacher who might be teaching this subject
|
|
teacher = random.choice(staff_members)
|
|
|
|
# Create 1-3 files for each selected subject
|
|
for i in range(random.randint(1, 3)):
|
|
file_types = ['Lecture Notes', 'Assignment', 'Reference Material', 'Exam Paper']
|
|
file_type = random.choice(file_types)
|
|
|
|
subject_file = SubjectFile(
|
|
subject=subject,
|
|
title=f"{file_type} - {subject.name} - {i+1}",
|
|
description=fake.paragraph(),
|
|
# Note: actual file content can't be created here
|
|
# file field would need an actual file
|
|
uploaded_by=teacher
|
|
)
|
|
|
|
try:
|
|
# We can't actually save this without a real file
|
|
# subject_file.save()
|
|
self.stdout.write(self.style.SUCCESS(f'Created subject file: {subject_file.title}'))
|
|
except:
|
|
# Skip if there's an error
|
|
pass
|
|
|
|
def _create_course_tracking(self, students, courses):
|
|
# Create course tracking records for students
|
|
for student in students:
|
|
course = student.course
|
|
|
|
if course:
|
|
try:
|
|
# Check if tracking already exists
|
|
existing_tracking = CourseTracking.objects.filter(
|
|
student=student,
|
|
course=course
|
|
).first()
|
|
|
|
if existing_tracking:
|
|
continue # Skip if tracking already exists
|
|
|
|
# Calculate dates based on student's joining date
|
|
joining_date = student.joining_date or datetime.now().date() - timedelta(days=random.randint(180, 365))
|
|
expected_end_date = joining_date + timedelta(days=365 * course.duration)
|
|
|
|
# Calculate completion percentage based on current semester
|
|
if course.duration_type == 'Semester':
|
|
total_semesters = course.duration * 2
|
|
completion_percentage = int((student.current_period / total_semesters) * 100)
|
|
else:
|
|
completion_percentage = int((student.current_period / course.duration) * 100)
|
|
|
|
# Determine progress status
|
|
if completion_percentage == 100:
|
|
progress_status = 'Completed'
|
|
elif completion_percentage == 0:
|
|
progress_status = 'Not Started'
|
|
else:
|
|
progress_status = 'In Progress'
|
|
|
|
tracking = CourseTracking(
|
|
student=student,
|
|
course=course,
|
|
enrollment_date=joining_date,
|
|
start_date=joining_date,
|
|
expected_end_date=expected_end_date,
|
|
actual_end_date=None,
|
|
progress_status=progress_status,
|
|
completion_percentage=completion_percentage,
|
|
current_period=student.current_period,
|
|
semester_start_date=joining_date,
|
|
notes=f"Tracking student progress in {course.name}"
|
|
)
|
|
tracking.save()
|
|
self.stdout.write(self.style.SUCCESS(f'Created course tracking for {student.name} in {course.name}'))
|
|
except Exception as e:
|
|
# Log the error but continue with other students
|
|
self.stdout.write(self.style.ERROR(f'Error creating course tracking for {student.name}: {str(e)}'))
|
|
continue # Continue with next student
|