diff --git a/apps/course/serializers/admin.py b/apps/course/serializers/admin.py index 3603fc0..2feb4f6 100644 --- a/apps/course/serializers/admin.py +++ b/apps/course/serializers/admin.py @@ -1,4 +1,4 @@ -from rest_framework import serializers +from rest_framework import serializers from utils import FileFieldSerializer, get_thumbs from apps.course.models import ( Course, @@ -185,12 +185,8 @@ class AdminCourseDetailSerializer(serializers.ModelSerializer): def to_representation(self, instance): ret = super().to_representation(instance) lang = get_request_lang(self) - ret['title'] = get_localized_field(lang, instance.title) - ret['slug'] = get_localized_field(lang, instance.slug) - ret['level'] = get_localized_field(lang, instance.level) - ret['status'] = get_localized_field(lang, instance.status) - ret['timing'] = get_localized_field(lang, instance.timing) - ret['features'] = get_localized_field(lang, instance.features) + # Keep raw JSON values here so the admin form can edit all language variants, + # matching the blog admin flow. return ret @@ -519,3 +515,4 @@ class AdminLiveSessionDetailSerializer(serializers.ModelSerializer): return "" lang = get_request_lang(self) return get_localized_field(lang, obj.course.title) + diff --git a/apps/course/serializers/course.py b/apps/course/serializers/course.py index 43a95eb..0e4ca39 100644 --- a/apps/course/serializers/course.py +++ b/apps/course/serializers/course.py @@ -5,6 +5,8 @@ from apps.course.models import Course, CourseCategory, Attachment, Glossary, Les from apps.course.models.course import get_localized_field from apps.chat.models import RoomMessage from apps.account.serializers import UserProfileSerializer +import ast +import json @@ -413,25 +415,62 @@ class CourseDetailSerializer(serializers.ModelSerializer): def get_status(self, obj): return get_localized_field(self._lang(), obj.status) + def _parse_builder_payload(self, value): + if value is None: + return None + if isinstance(value, str): + for parser in (json.loads, ast.literal_eval): + try: + parsed = parser(value) + return parsed + except Exception: + continue + return value + return value + + def _extract_builder_list(self, value): + """ + Return the raw builder list for the current language. + Supports both: + - direct lists like [{'day': 'monday', 'timing': '12:22'}, ...] + - multilingual wrappers like [{'language_code': 'en', 'title': "[...]"}, ...] + """ + parsed = self._parse_builder_payload(value) + if parsed is None: + return [] + + if isinstance(parsed, list) and parsed: + if all(isinstance(item, dict) and 'language_code' in item for item in parsed): + current_lang = self._lang() + selected = next( + ( + item for item in parsed + if isinstance(item, dict) and item.get('language_code') == current_lang + ), + parsed[0], + ) + parsed = self._parse_builder_payload( + selected.get('title') + or selected.get('text') + or selected.get('value') + or selected.get('name') + or [] + ) + + if isinstance(parsed, list): + return parsed + if isinstance(parsed, dict): + if isinstance(parsed.get('list'), list): + return parsed['list'] + if isinstance(parsed.get('items'), list): + return parsed['items'] + return [] + def get_timing(self, obj): - import json - val = get_localized_field(self._lang(), obj.timing) - if isinstance(val, str): - try: - return json.loads(val) - except Exception: - pass - return val + return self._extract_builder_list(obj.timing) def get_features(self, obj): - import json - val = get_localized_field(self._lang(), obj.features) - if isinstance(val, str): - try: - return json.loads(val) - except Exception: - pass - return val + return self._extract_builder_list(obj.features) @@ -594,4 +633,4 @@ class CourseGlossarySerializer(serializers.ModelSerializer): return getattr(request, 'LANGUAGE_CODE', None) or 'en' def get_description(self, obj): - return get_localized_field(self._lang(), obj.glossary.description) \ No newline at end of file + return get_localized_field(self._lang(), obj.glossary.description)