|
8 | 8 | from ediauth.models import Profile |
9 | 9 | from answers.models import Answer, AnswerSection, Comment, Exam, ExamType |
10 | 10 | from documents.models import DocumentType, Document, DocumentFile |
11 | | -from categories.models import Category, MetaCategory, EuclidCode |
| 11 | +from categories.models import Category, MetaCategory, EuclidCode, CourseStats |
12 | 12 | from feedback.models import Feedback |
13 | 13 | from filestore.models import Attachment |
14 | 14 | from images.models import Image |
15 | 15 | from notifications.models import Notification, NotificationSetting, NotificationType |
16 | 16 | import os |
| 17 | +import random |
17 | 18 | from answers import pdf_utils |
18 | 19 |
|
19 | 20 |
|
@@ -329,12 +330,87 @@ def create_documents(self): |
329 | 330 | if (i + user.id) % 4 == 0: |
330 | 331 | document.likes.add(user) |
331 | 332 |
|
| 333 | + def create_course_stats(self): |
| 334 | + self.stdout.write("Create course statistics") |
| 335 | + |
| 336 | + # Generate realistic course names for Informatics courses |
| 337 | + course_name_patterns = [ |
| 338 | + "Algorithms and Data Structures", |
| 339 | + "Secure Programming", |
| 340 | + "Machine Learning", |
| 341 | + "Software Engineering and Professional Practice", |
| 342 | + "Introduction to Databases", |
| 343 | + "Systems Design Project", |
| 344 | + "Operating Systems", |
| 345 | + "Human-Computer Interaction", |
| 346 | + "Reasoning and Agents", |
| 347 | + "Cyber Security", |
| 348 | + "Applied Cloud Programming", |
| 349 | + "Distributed Systems", |
| 350 | + "Computer Vision", |
| 351 | + ] |
| 352 | + |
| 353 | + # Academic years from 2017-18 to 2024-25 |
| 354 | + academic_years = [ |
| 355 | + "2017-18", |
| 356 | + "2018-19", |
| 357 | + "2019-20", |
| 358 | + "2020-21", |
| 359 | + "2021-22", |
| 360 | + "2022-23", |
| 361 | + "2023-24", |
| 362 | + "2024-25", |
| 363 | + ] |
| 364 | + |
| 365 | + objs = [] |
| 366 | + |
| 367 | + # Get all Euclid codes from categories |
| 368 | + euclid_codes = EuclidCode.objects.all() |
| 369 | + |
| 370 | + for euclid_code in euclid_codes: |
| 371 | + # Pick a random course name pattern |
| 372 | + base_course_name = random.choice(course_name_patterns) |
| 373 | + course_name = f"{base_course_name} ({euclid_code.category.displayname})" |
| 374 | + |
| 375 | + # Generate stats for each academic year |
| 376 | + for year in academic_years: |
| 377 | + # Generate realistic grade statistics |
| 378 | + # Mean marks typically range from 45-85, with most courses 55-75 |
| 379 | + base_mean = random.uniform(55, 75) |
| 380 | + |
| 381 | + # Add some year-to-year variation (-5 to +5) |
| 382 | + year_variation = random.uniform(-5, 5) |
| 383 | + mean_mark = max(45, min(85, base_mean + year_variation)) |
| 384 | + |
| 385 | + # Standard deviation typically 10-25, with most 12-20 |
| 386 | + std_deviation = random.uniform(12, 20) |
| 387 | + |
| 388 | + # Some years might have missing data (simulate N/A values) |
| 389 | + if random.random() < 0.05: # 5% chance of missing data |
| 390 | + mean_mark = None |
| 391 | + std_deviation = None |
| 392 | + |
| 393 | + objs.append( |
| 394 | + CourseStats( |
| 395 | + course_name=course_name, |
| 396 | + course_code=euclid_code.code, |
| 397 | + mean_mark=mean_mark, |
| 398 | + std_deviation=std_deviation, |
| 399 | + academic_year=year, |
| 400 | + ) |
| 401 | + ) |
| 402 | + |
| 403 | + # Bulk create all course stats |
| 404 | + CourseStats.objects.bulk_create(objs, ignore_conflicts=True) |
| 405 | + self.stdout.write(f"Created {len(objs)} course statistics entries") |
| 406 | + |
332 | 407 | def handle(self, *args, **options): |
333 | 408 | self.flush_db() |
334 | 409 | self.create_users() |
335 | 410 | self.create_images() |
336 | 411 | self.create_meta_categories() |
337 | 412 | self.create_categories() |
| 413 | + self.create_course_stats() |
338 | 414 | self.create_exam_types() |
339 | 415 | self.create_exams() |
340 | 416 | self.create_answer_sections() |
|
0 commit comments