Browse Source

fix(serializers): handle non-dict and string items safely in LocalizedField and reference author names

master
Mohsen Taba 3 weeks ago
parent
commit
fe7d468a59
  1. 57
      apps/hadis/serializers/category.py
  2. 31
      apps/hadis/serializers/reference.py

57
apps/hadis/serializers/category.py

@ -8,11 +8,15 @@ from django.utils.translation import get_language
def _get_localized_item_value(item):
"""
Prefer `title`, but fall back to `text` for older/mis-shaped localized entries.
Prefer `title`, but fall back to `text` or `name` for older/mis-shaped localized entries.
"""
if not isinstance(item, dict):
if not item:
return None
return item.get("title") or item.get("text")
if isinstance(item, str):
return item
if isinstance(item, dict):
return item.get("title") or item.get("text") or item.get("name")
return str(item)
def get_localized_text(json_list, request=None, fallback_lang="en", language_code=None):
"""
@ -23,8 +27,12 @@ def get_localized_text(json_list, request=None, fallback_lang="en", language_cod
- {"language_code": "en", "text": "..."}
Returns: Single text string or None
"""
if not json_list or not isinstance(json_list, list):
if not json_list:
return None
if isinstance(json_list, str):
return json_list
if not isinstance(json_list, list):
return _get_localized_item_value(json_list)
# Get target language if not provided
if not language_code:
@ -47,14 +55,18 @@ def get_localized_text(json_list, request=None, fallback_lang="en", language_cod
return value
# 3) First available
if json_list and isinstance(json_list[0], dict):
if json_list:
return _get_localized_item_value(json_list[0])
return None
def get_arabic_localized_text(json_list):
if not json_list or not isinstance(json_list, list):
if not json_list:
return None
if isinstance(json_list, str):
return json_list
if not isinstance(json_list, list):
return _get_localized_item_value(json_list)
# 1) Exact match for 'ar'
for item in json_list:
@ -63,7 +75,7 @@ def get_arabic_localized_text(json_list):
if value: return value
# 2) Fallback to the last item registered
if json_list and isinstance(json_list[-1], dict):
if json_list:
return _get_localized_item_value(json_list[-1])
return None
@ -77,33 +89,37 @@ class LocalizedField(serializers.Field):
"""
def to_representation(self, value):
# Expecting value to be a list of localized dicts using `title` or `text`
if not value or not isinstance(value, list):
if not value:
return None
if isinstance(value, str):
return value
if not isinstance(value, list):
return _get_localized_item_value(value)
# Get language from request, then fall back to global language / 'fa'
request = self.context.get("request")
language_code = getattr(request, "LANGUAGE_CODE", None) if request else None
if not language_code:
language_code = get_language() or "fa" # global active language [web:164][web:172]
language_code = get_language() or "fa" # global active language
# 1) Exact match with request language
for item in value:
if item.get("language_code") == language_code:
if isinstance(item, dict) and item.get("language_code") == language_code:
localized_value = _get_localized_item_value(item)
if localized_value:
return localized_value
# 2) Fallback to English
for item in value:
if item.get("language_code") == "en":
if isinstance(item, dict) and item.get("language_code") == "en":
localized_value = _get_localized_item_value(item)
if localized_value:
return localized_value
# 3) Fallback to first item
first = value[0]
return _get_localized_item_value(first)
if value:
return _get_localized_item_value(value[0])
return None
class ArabicLocalizedField(serializers.Field):
"""
@ -111,17 +127,22 @@ class ArabicLocalizedField(serializers.Field):
or falls back to the last item in the list if 'ar' is not found.
"""
def to_representation(self, value):
if not value or not isinstance(value, list):
if not value:
return None
if isinstance(value, str):
return value
if not isinstance(value, list):
return _get_localized_item_value(value)
for item in value:
if item.get("language_code") == "ar":
if isinstance(item, dict) and item.get("language_code") == "ar":
localized_value = _get_localized_item_value(item)
if localized_value:
return localized_value
last = value[-1]
return _get_localized_item_value(last)
if value:
return _get_localized_item_value(value[-1])
return None
class SimpleCategory(serializers.ModelSerializer):
title = LocalizedField()

31
apps/hadis/serializers/reference.py

@ -52,22 +52,23 @@ class BookReferenceSerializer(serializers.ModelSerializer):
result = []
for author in authors:
# author.name is your list of dicts
name_items = author.name or []
# find item with matching language_code
text = None
for item in name_items:
if item.get("language_code") == language_code:
print(f'we got language-code{language_code}')
text = item.get("text")
break
# fallback: if not found, use first item or None
print(text,'this is text')
if text is None and name_items:
print('no we didnt')
text = name_items[0].get("text")
if isinstance(name_items, str):
text = name_items
elif isinstance(name_items, list):
text = None
for item in name_items:
if isinstance(item, dict) and item.get("language_code") == language_code:
text = item.get("text") or item.get("title") or item.get("name")
break
if text is None and name_items:
first = name_items[0]
if isinstance(first, dict):
text = first.get("text") or first.get("title") or first.get("name")
elif isinstance(first, str):
text = first
else:
text = str(name_items) if name_items else None
result.append(
{

Loading…
Cancel
Save