Skip to content

Commit 6847a9a

Browse files
committed
Add support for multi-curriculum batches and enhance curriculum options management
1 parent 366f353 commit 6847a9a

File tree

4 files changed

+143
-41
lines changed

4 files changed

+143
-41
lines changed

FusionIIIT/applications/programme_curriculum/api/views.py

Lines changed: 71 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -536,11 +536,33 @@ def Admin_view_all_working_curriculums(request):
536536
# Manually serialize the curriculums into a list of dictionaries
537537
curriculum_data = []
538538
for curriculum in curriculums:
539+
primary_batches = curriculum.batches.all()
540+
541+
from django.db.models import Q
542+
multi_curriculum_batches = Batch.objects.filter(
543+
curriculum_options__isnull=False
544+
).exclude(
545+
curriculum_options=[]
546+
)
547+
548+
batches_with_this_curriculum = []
549+
for batch in primary_batches:
550+
batches_with_this_curriculum.append(batch)
551+
552+
for batch in multi_curriculum_batches:
553+
if batch.curriculum_options:
554+
for curr_option in batch.curriculum_options:
555+
if curr_option.get('id') == curriculum.id:
556+
batches_with_this_curriculum.append(batch)
557+
break
558+
559+
unique_batches = list(set(batches_with_this_curriculum))
560+
539561
curriculum_data.append({
540562
'id':curriculum.id,
541563
'name': curriculum.name,
542564
'version': str(curriculum.version), # Convert Decimal to string for JSON compatibility
543-
'batch': [str(batch) for batch in curriculum.batches], # Use batches property from model
565+
'batch': [str(batch) for batch in unique_batches], # Include both primary and multi-curriculum batches
544566
'semesters': curriculum.no_of_semester,
545567
})
546568

@@ -1833,7 +1855,7 @@ def edit_batch_form(request, batch_id):
18331855
curricula_data = [{
18341856
'id': curriculum.id,
18351857
'name': curriculum.name,
1836-
'version': curriculum.version,
1858+
'version': str(curriculum.version),
18371859
# Uncomment these if you want to include discipline and programme details
18381860
# 'discipline': curriculum.discipline.name,
18391861
# 'programme': curriculum.programme.name,
@@ -1870,16 +1892,52 @@ def edit_batch_form(request, batch_id):
18701892
except Discipline.DoesNotExist:
18711893
return JsonResponse({'error': 'Invalid discipline ID'}, status=400)
18721894

1873-
# Update curriculum (if provided)
1874-
curriculum_id = data.get('disciplineBatch')
1875-
if curriculum_id:
1876-
try:
1877-
curriculum = Curriculum.objects.get(id=curriculum_id)
1878-
batch.curriculum = curriculum
1879-
except Curriculum.DoesNotExist:
1880-
return JsonResponse({'error': 'Invalid curriculum ID'}, status=400)
1881-
else:
1882-
batch.curriculum = None # Set curriculum to None if not provided
1895+
curriculum_data = data.get('disciplineBatch') or data.get('curriculum') or data.get('curriculum_data')
1896+
if curriculum_data is not None:
1897+
# Normalize to list of ids if possible
1898+
curriculum_ids = []
1899+
if isinstance(curriculum_data, list):
1900+
curriculum_ids = curriculum_data
1901+
elif isinstance(curriculum_data, str):
1902+
if ',' in curriculum_data:
1903+
curriculum_ids = [c.strip() for c in curriculum_data.split(',') if c.strip()]
1904+
elif curriculum_data.lower() in ['null', 'none', '']:
1905+
curriculum_ids = []
1906+
else:
1907+
curriculum_ids = [curriculum_data]
1908+
else:
1909+
curriculum_ids = [curriculum_data]
1910+
1911+
if len(curriculum_ids) > 1:
1912+
option_list = []
1913+
for cid in curriculum_ids:
1914+
try:
1915+
c_obj = Curriculum.objects.get(id=int(cid))
1916+
option_list.append({'id': c_obj.id, 'name': c_obj.name, 'version': str(c_obj.version)})
1917+
except (Curriculum.DoesNotExist, ValueError):
1918+
return JsonResponse({'error': f'Invalid curriculum ID: {cid}'}, status=400)
1919+
batch.curriculum = None
1920+
try:
1921+
batch.curriculum_options = option_list
1922+
except Exception:
1923+
pass
1924+
elif len(curriculum_ids) == 1:
1925+
# Single curriculum selected
1926+
try:
1927+
c_obj = Curriculum.objects.get(id=int(curriculum_ids[0]))
1928+
batch.curriculum = c_obj
1929+
try:
1930+
batch.curriculum_options = None
1931+
except Exception:
1932+
pass
1933+
except (Curriculum.DoesNotExist, ValueError):
1934+
return JsonResponse({'error': 'Invalid curriculum ID'}, status=400)
1935+
else:
1936+
batch.curriculum = None
1937+
try:
1938+
batch.curriculum_options = None
1939+
except Exception:
1940+
pass
18831941

18841942
# Save the updated batch
18851943
batch.save()
@@ -3215,7 +3273,6 @@ def course_slot_type_choices(request):
32153273
API endpoint to return the list of course slot type choices from the CourseSlot model.
32163274
"""
32173275
choices = [{'value': key, 'label': label} for key, label in CourseSlot._meta.get_field('type').choices]
3218-
# print(choices)
32193276
return JsonResponse({'choices': choices})
32203277

32213278
@csrf_exempt
@@ -3277,14 +3334,6 @@ def get_programme(request, programme_id):
32773334
@permission_classes([IsAuthenticated])
32783335
def get_batch_names(request):
32793336
choices = [{'value': key, 'label': label} for key, label in Batch._meta.get_field('name').choices]
3280-
# print('choices',choices)
3281-
3282-
# batch_names = Batch.objects.values_list('name', flat=True).distinct()
3283-
# print(batch_names)
3284-
# # Convert the QuerySet to a list
3285-
# batch_names_list = list(batch_names)
3286-
# print(batch_names_list)
3287-
# Return the list as a JSON response
32883337
return JsonResponse({'choices': choices})
32893338

32903339
@csrf_exempt
@@ -3309,13 +3358,9 @@ def get_all_disciplines(request):
33093358
@csrf_exempt
33103359
@permission_classes([IsAuthenticated])
33113360
def get_unused_curriculam(request):
3312-
# Fetch all curriculum IDs that are present in the Batch table
33133361
used_curriculum_ids = Batch.objects.exclude(curriculum__isnull=True).values_list('curriculum_id', flat=True)
3314-
3315-
# Fetch curricula whose IDs are not in the used_curriculum_ids list
33163362
unused_curricula = Curriculum.objects.exclude(id__in=used_curriculum_ids)
3317-
3318-
# Serialize the unused curricula
3363+
# ...existing code...
33193364
unused_curricula_data = [
33203365
{
33213366
'id': curriculum.id,

FusionIIIT/applications/programme_curriculum/api/views_student_management.py

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2128,7 +2128,7 @@ def create_batch(request):
21282128
}, status=400)
21292129

21302130
# Students will be assigned specific curriculums when they become REPORTED based on specialization
2131-
if programme == 'M.Tech' and len(curriculum_objs) > 1:
2131+
if programme in ['M.Tech', 'M.Des', 'Phd'] and len(curriculum_objs) > 1:
21322132
primary_curriculum = None
21332133
elif len(curriculum_objs) == 1:
21342134
primary_curriculum = curriculum_objs[0]
@@ -2144,7 +2144,7 @@ def create_batch(request):
21442144
else:
21452145
return JsonResponse({
21462146
'success': False,
2147-
'message': f'Multiple curriculum assignment is currently only supported for M.Tech programmes.',
2147+
'message': f'Multiple curriculum assignment is currently only supported for PG programmes (M.Tech, M.Des, Phd).',
21482148
'validation_error': 'unsupported_multi_curriculum'
21492149
}, status=400)
21502150

@@ -2198,6 +2198,23 @@ def create_batch(request):
21982198
'message': f'Failed to create batch: {str(batch_error)}'
21992199
}, status=500)
22002200

2201+
# Persist curriculum options for multi-curriculum batches (all PG programmes)
2202+
if programme in ['M.Tech', 'M.Des', 'Phd'] and len(curriculum_objs) > 1:
2203+
try:
2204+
batch.curriculum_options = [
2205+
{'id': c.id, 'name': c.name, 'version': c.version} for c in curriculum_objs
2206+
]
2207+
batch.save()
2208+
except Exception:
2209+
# Non-fatal: we already created the batch; just continue
2210+
pass
2211+
else:
2212+
# Clear any previous options for single-curriculum batches
2213+
try:
2214+
batch.curriculum_options = None
2215+
batch.save()
2216+
except Exception:
2217+
pass
22012218
if programme == 'M.Tech' and len(curriculum_objs) > 1:
22022219
success_message = f'Multi-curriculum M.Tech batch created! Students will be auto-assigned to curriculums based on their specialization.'
22032220
curriculum_info = {
@@ -2483,36 +2500,57 @@ def auto_generate_passwords_for_batch(request):
24832500
def get_available_curriculums_for_batch(batch_obj):
24842501
"""
24852502
Get available curriculums for a batch based on programme and discipline
2486-
For multi-curriculum M.Tech batches, return all relevant curriculums
2503+
For multi-curriculum PG batches (M.Tech, M.Des), return all relevant curriculums
24872504
"""
24882505
if not batch_obj:
24892506
return []
24902507

24912508
from applications.programme_curriculum.models import Curriculum
24922509

2493-
# Check if this is a multi-curriculum M.Tech batch
2494-
if batch_obj.name == 'M.Tech' and not batch_obj.curriculum:
2510+
if hasattr(batch_obj, 'curriculum_options') and batch_obj.curriculum_options:
2511+
return batch_obj.curriculum_options
2512+
2513+
# Check if this is a multi-curriculum PG batch (M.Tech, M.Des, PhD, etc.)
2514+
if batch_obj.name in ['M.Tech', 'M.Des', 'Phd'] and not batch_obj.curriculum:
24952515
# Get all working curriculums for this discipline and programme
24962516
available_curriculums = Curriculum.objects.filter(
24972517
working_curriculum=True,
2498-
programme__name__icontains='M.Tech'
2518+
programme__name__icontains=batch_obj.name
24992519
)
25002520

25012521
# Filter by discipline if possible (based on common patterns)
25022522
discipline_name = batch_obj.discipline.name.lower()
2523+
discipline_filtered = available_curriculums
2524+
2525+
# Apply discipline-specific filtering for various disciplines
25032526
if 'computer science' in discipline_name or 'cse' in discipline_name:
2504-
# Return CSE-related curriculums
2505-
cse_curriculums = available_curriculums.filter(
2506-
Q(name__icontains='CSE') |
2507-
Q(name__icontains='AI') |
2527+
discipline_filtered = available_curriculums.filter(
2528+
Q(name__icontains='AI') |
25082529
Q(name__icontains='Data Science') |
25092530
Q(name__icontains='Computer Science')
25102531
)
2511-
if cse_curriculums.exists():
2512-
return [{'id': c.id, 'name': c.name, 'version': c.version} for c in cse_curriculums]
2513-
2514-
# Fallback to all M.Tech curriculums
2515-
return [{'id': c.id, 'name': c.name, 'version': c.version} for c in available_curriculums]
2532+
elif 'electronics' in discipline_name or 'ece' in discipline_name:
2533+
discipline_filtered = available_curriculums.filter(
2534+
Q(name__icontains='Communication and Signal Processing') |
2535+
Q(name__icontains='Nanoelectronics and VLSI Design') |
2536+
Q(name__icontains='Power & Control')
2537+
)
2538+
elif 'mechanical engineering' in discipline_name or 'me' in discipline_name:
2539+
discipline_filtered = available_curriculums.filter(
2540+
Q(name__icontains='Design') |
2541+
Q(name__icontains='CAD/CAM') |
2542+
Q(name__icontains='Manufacturing and Automation')
2543+
)
2544+
elif 'mechatronics' in discipline_name or 'mt' in discipline_name:
2545+
discipline_filtered = available_curriculums.filter(
2546+
Q(name__icontains='Mechatronics')
2547+
)
2548+
elif 'design' in discipline_name or 'des' in discipline_name:
2549+
discipline_filtered = available_curriculums.filter(
2550+
Q(name__icontains='Design')
2551+
)
2552+
final_curriculums = discipline_filtered if discipline_filtered.exists() else available_curriculums
2553+
return [{'id': c.id, 'name': c.name, 'version': c.version} for c in final_curriculums]
25162554

25172555
elif batch_obj.curriculum:
25182556
# Single curriculum batch
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 3.1.5 on 2025-11-12 23:14
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('programme_curriculum', '0030_add_specialization_field'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='batch',
15+
name='curriculum_options',
16+
field=models.JSONField(blank=True, null=True),
17+
),
18+
]

FusionIIIT/applications/programme_curriculum/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ class Batch(models.Model):
231231
default=datetime.date.today().year, null=False)
232232
curriculum = models.ForeignKey(
233233
Curriculum, null=True, blank=True, on_delete=models.SET_NULL)
234+
curriculum_options = models.JSONField(null=True, blank=True)
234235
running_batch = models.BooleanField(default=True)
235236
total_seats = models.PositiveIntegerField(default=60, null=False, blank=False)
236237

0 commit comments

Comments
 (0)