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): 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 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): 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": "..."} - {"language_code": "en", "text": "..."}
Returns: Single text string or None Returns: Single text string or None
""" """
if not json_list or not isinstance(json_list, list):
if not json_list:
return None 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 # Get target language if not provided
if not language_code: if not language_code:
@ -47,14 +55,18 @@ def get_localized_text(json_list, request=None, fallback_lang="en", language_cod
return value return value
# 3) First available # 3) First available
if json_list and isinstance(json_list[0], dict):
if json_list:
return _get_localized_item_value(json_list[0]) return _get_localized_item_value(json_list[0])
return None return None
def get_arabic_localized_text(json_list): def get_arabic_localized_text(json_list):
if not json_list or not isinstance(json_list, list):
if not json_list:
return None 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' # 1) Exact match for 'ar'
for item in json_list: for item in json_list:
@ -63,7 +75,7 @@ def get_arabic_localized_text(json_list):
if value: return value if value: return value
# 2) Fallback to the last item registered # 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 _get_localized_item_value(json_list[-1])
return None return None
@ -77,33 +89,37 @@ class LocalizedField(serializers.Field):
""" """
def to_representation(self, value): 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 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' # Get language from request, then fall back to global language / 'fa'
request = self.context.get("request") request = self.context.get("request")
language_code = getattr(request, "LANGUAGE_CODE", None) if request else None language_code = getattr(request, "LANGUAGE_CODE", None) if request else None
if not language_code: 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 # 1) Exact match with request language
for item in value: 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) localized_value = _get_localized_item_value(item)
if localized_value: if localized_value:
return localized_value return localized_value
# 2) Fallback to English # 2) Fallback to English
for item in value: 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) localized_value = _get_localized_item_value(item)
if localized_value: if localized_value:
return localized_value return localized_value
# 3) Fallback to first item # 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): 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. or falls back to the last item in the list if 'ar' is not found.
""" """
def to_representation(self, value): def to_representation(self, value):
if not value or not isinstance(value, list):
if not value:
return None return None
if isinstance(value, str):
return value
if not isinstance(value, list):
return _get_localized_item_value(value)
for item in 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) localized_value = _get_localized_item_value(item)
if localized_value: if localized_value:
return 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): class SimpleCategory(serializers.ModelSerializer):
title = LocalizedField() title = LocalizedField()

31
apps/hadis/serializers/reference.py

@ -52,22 +52,23 @@ class BookReferenceSerializer(serializers.ModelSerializer):
result = [] result = []
for author in authors: for author in authors:
# author.name is your list of dicts
name_items = author.name or [] 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( result.append(
{ {

Loading…
Cancel
Save