Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 71 additions & 26 deletions FusionIIIT/applications/programme_curriculum/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,11 +536,33 @@ def Admin_view_all_working_curriculums(request):
# Manually serialize the curriculums into a list of dictionaries
curriculum_data = []
for curriculum in curriculums:
primary_batches = curriculum.batches.all()

from django.db.models import Q
multi_curriculum_batches = Batch.objects.filter(
curriculum_options__isnull=False
).exclude(
curriculum_options=[]
)

batches_with_this_curriculum = []
for batch in primary_batches:
batches_with_this_curriculum.append(batch)

for batch in multi_curriculum_batches:
if batch.curriculum_options:
for curr_option in batch.curriculum_options:
if curr_option.get('id') == curriculum.id:
batches_with_this_curriculum.append(batch)
break

unique_batches = list(set(batches_with_this_curriculum))

curriculum_data.append({
'id':curriculum.id,
'name': curriculum.name,
'version': str(curriculum.version), # Convert Decimal to string for JSON compatibility
'batch': [str(batch) for batch in curriculum.batches], # Use batches property from model
'batch': [str(batch) for batch in unique_batches], # Include both primary and multi-curriculum batches
'semesters': curriculum.no_of_semester,
})

Expand Down Expand Up @@ -1833,7 +1855,7 @@ def edit_batch_form(request, batch_id):
curricula_data = [{
'id': curriculum.id,
'name': curriculum.name,
'version': curriculum.version,
'version': str(curriculum.version),
# Uncomment these if you want to include discipline and programme details
# 'discipline': curriculum.discipline.name,
# 'programme': curriculum.programme.name,
Expand Down Expand Up @@ -1870,16 +1892,52 @@ def edit_batch_form(request, batch_id):
except Discipline.DoesNotExist:
return JsonResponse({'error': 'Invalid discipline ID'}, status=400)

# Update curriculum (if provided)
curriculum_id = data.get('disciplineBatch')
if curriculum_id:
try:
curriculum = Curriculum.objects.get(id=curriculum_id)
batch.curriculum = curriculum
except Curriculum.DoesNotExist:
return JsonResponse({'error': 'Invalid curriculum ID'}, status=400)
else:
batch.curriculum = None # Set curriculum to None if not provided
curriculum_data = data.get('disciplineBatch') or data.get('curriculum') or data.get('curriculum_data')
if curriculum_data is not None:
# Normalize to list of ids if possible
curriculum_ids = []
if isinstance(curriculum_data, list):
curriculum_ids = curriculum_data
elif isinstance(curriculum_data, str):
if ',' in curriculum_data:
curriculum_ids = [c.strip() for c in curriculum_data.split(',') if c.strip()]
elif curriculum_data.lower() in ['null', 'none', '']:
curriculum_ids = []
else:
curriculum_ids = [curriculum_data]
else:
curriculum_ids = [curriculum_data]

if len(curriculum_ids) > 1:
option_list = []
for cid in curriculum_ids:
try:
c_obj = Curriculum.objects.get(id=int(cid))
option_list.append({'id': c_obj.id, 'name': c_obj.name, 'version': str(c_obj.version)})
except (Curriculum.DoesNotExist, ValueError):
return JsonResponse({'error': f'Invalid curriculum ID: {cid}'}, status=400)
batch.curriculum = None
try:
batch.curriculum_options = option_list
except Exception:
pass
elif len(curriculum_ids) == 1:
# Single curriculum selected
try:
c_obj = Curriculum.objects.get(id=int(curriculum_ids[0]))
batch.curriculum = c_obj
try:
batch.curriculum_options = None
except Exception:
pass
except (Curriculum.DoesNotExist, ValueError):
return JsonResponse({'error': 'Invalid curriculum ID'}, status=400)
else:
batch.curriculum = None
try:
batch.curriculum_options = None
except Exception:
pass

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

@csrf_exempt
Expand Down Expand Up @@ -3277,14 +3334,6 @@ def get_programme(request, programme_id):
@permission_classes([IsAuthenticated])
def get_batch_names(request):
choices = [{'value': key, 'label': label} for key, label in Batch._meta.get_field('name').choices]
# print('choices',choices)

# batch_names = Batch.objects.values_list('name', flat=True).distinct()
# print(batch_names)
# # Convert the QuerySet to a list
# batch_names_list = list(batch_names)
# print(batch_names_list)
# Return the list as a JSON response
return JsonResponse({'choices': choices})

@csrf_exempt
Expand All @@ -3309,13 +3358,9 @@ def get_all_disciplines(request):
@csrf_exempt
@permission_classes([IsAuthenticated])
def get_unused_curriculam(request):
# Fetch all curriculum IDs that are present in the Batch table
used_curriculum_ids = Batch.objects.exclude(curriculum__isnull=True).values_list('curriculum_id', flat=True)

# Fetch curricula whose IDs are not in the used_curriculum_ids list
unused_curricula = Curriculum.objects.exclude(id__in=used_curriculum_ids)

# Serialize the unused curricula
# ...existing code...
unused_curricula_data = [
{
'id': curriculum.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2128,7 +2128,7 @@ def create_batch(request):
}, status=400)

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

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

# Persist curriculum options for multi-curriculum batches (all PG programmes)
if programme in ['M.Tech', 'M.Des', 'Phd'] and len(curriculum_objs) > 1:
try:
batch.curriculum_options = [
{'id': c.id, 'name': c.name, 'version': c.version} for c in curriculum_objs
]
batch.save()
except Exception:
# Non-fatal: we already created the batch; just continue
pass
else:
# Clear any previous options for single-curriculum batches
try:
batch.curriculum_options = None
batch.save()
except Exception:
pass
if programme == 'M.Tech' and len(curriculum_objs) > 1:
success_message = f'Multi-curriculum M.Tech batch created! Students will be auto-assigned to curriculums based on their specialization.'
curriculum_info = {
Expand Down Expand Up @@ -2483,36 +2500,57 @@ def auto_generate_passwords_for_batch(request):
def get_available_curriculums_for_batch(batch_obj):
"""
Get available curriculums for a batch based on programme and discipline
For multi-curriculum M.Tech batches, return all relevant curriculums
For multi-curriculum PG batches (M.Tech, M.Des), return all relevant curriculums
"""
if not batch_obj:
return []

from applications.programme_curriculum.models import Curriculum

# Check if this is a multi-curriculum M.Tech batch
if batch_obj.name == 'M.Tech' and not batch_obj.curriculum:
if hasattr(batch_obj, 'curriculum_options') and batch_obj.curriculum_options:
return batch_obj.curriculum_options

# Check if this is a multi-curriculum PG batch (M.Tech, M.Des, PhD, etc.)
if batch_obj.name in ['M.Tech', 'M.Des', 'Phd'] and not batch_obj.curriculum:
# Get all working curriculums for this discipline and programme
available_curriculums = Curriculum.objects.filter(
working_curriculum=True,
programme__name__icontains='M.Tech'
programme__name__icontains=batch_obj.name
)

# Filter by discipline if possible (based on common patterns)
discipline_name = batch_obj.discipline.name.lower()
discipline_filtered = available_curriculums

# Apply discipline-specific filtering for various disciplines
if 'computer science' in discipline_name or 'cse' in discipline_name:
# Return CSE-related curriculums
cse_curriculums = available_curriculums.filter(
Q(name__icontains='CSE') |
Q(name__icontains='AI') |
discipline_filtered = available_curriculums.filter(
Q(name__icontains='AI') |
Q(name__icontains='Data Science') |
Q(name__icontains='Computer Science')
)
if cse_curriculums.exists():
return [{'id': c.id, 'name': c.name, 'version': c.version} for c in cse_curriculums]

# Fallback to all M.Tech curriculums
return [{'id': c.id, 'name': c.name, 'version': c.version} for c in available_curriculums]
elif 'electronics' in discipline_name or 'ece' in discipline_name:
discipline_filtered = available_curriculums.filter(
Q(name__icontains='Communication and Signal Processing') |
Q(name__icontains='Nanoelectronics and VLSI Design') |
Q(name__icontains='Power & Control')
)
elif 'mechanical engineering' in discipline_name or 'me' in discipline_name:
discipline_filtered = available_curriculums.filter(
Q(name__icontains='Design') |
Q(name__icontains='CAD/CAM') |
Q(name__icontains='Manufacturing and Automation')
)
elif 'mechatronics' in discipline_name or 'mt' in discipline_name:
discipline_filtered = available_curriculums.filter(
Q(name__icontains='Mechatronics')
)
elif 'design' in discipline_name or 'des' in discipline_name:
discipline_filtered = available_curriculums.filter(
Q(name__icontains='Design')
)
final_curriculums = discipline_filtered if discipline_filtered.exists() else available_curriculums
return [{'id': c.id, 'name': c.name, 'version': c.version} for c in final_curriculums]

elif batch_obj.curriculum:
# Single curriculum batch
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.1.5 on 2025-11-12 23:14

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('programme_curriculum', '0030_add_specialization_field'),
]

operations = [
migrations.AddField(
model_name='batch',
name='curriculum_options',
field=models.JSONField(blank=True, null=True),
),
]
1 change: 1 addition & 0 deletions FusionIIIT/applications/programme_curriculum/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ class Batch(models.Model):
default=datetime.date.today().year, null=False)
curriculum = models.ForeignKey(
Curriculum, null=True, blank=True, on_delete=models.SET_NULL)
curriculum_options = models.JSONField(null=True, blank=True)
running_batch = models.BooleanField(default=True)
total_seats = models.PositiveIntegerField(default=60, null=False, blank=False)

Expand Down