From dd12d10bf44399ab0d4e01ae65f0049413c8dcd5 Mon Sep 17 00:00:00 2001 From: mohsentaba Date: Mon, 31 Aug 2026 12:27:33 +0330 Subject: [PATCH] feat(hadis): support list/JSON address storage and serialization for original texts, explanations, and corrections --- apps/hadis/serializers/hadis.py | 32 ++++++++--- apps/hadis/serializers/serializers_admin.py | 60 +++++++++++++++------ 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/apps/hadis/serializers/hadis.py b/apps/hadis/serializers/hadis.py index 64205df..015f700 100644 --- a/apps/hadis/serializers/hadis.py +++ b/apps/hadis/serializers/hadis.py @@ -416,6 +416,26 @@ class TransmitterOpinionSerializer(serializers.ModelSerializer): } return None +def format_address_output(ref): + if not ref or not ref.address: + return [] + addr = ref.address + if isinstance(addr, str): + trimmed = addr.strip() + if trimmed.startswith("["): + try: + import json + parsed = json.loads(trimmed) + if isinstance(parsed, list): + return parsed + except (ValueError, TypeError): + pass + return [addr] if trimmed else [] + elif isinstance(addr, list): + return addr + return [str(addr)] + + class TransmitterOriginalTextSerializer(serializers.ModelSerializer): """ Serializer for TransmitterOriginalText """ title = LocalizedField() @@ -429,8 +449,7 @@ class TransmitterOriginalTextSerializer(serializers.ModelSerializer): fields = ['id', 'title', 'text', 'translation', 'share_link', 'slug', 'address', 'images'] def get_address(self, obj): - ref = obj.references.first() - return ref.address if ref and ref.address else "" + return format_address_output(obj.references.first()) def get_images(self, obj): request = self.context.get('request') @@ -932,8 +951,7 @@ class HadisCorrectionSerializer(serializers.ModelSerializer): return book_mark.get('is_bookmarked', False) def get_address(self, obj): - ref = obj.references.first() - return ref.address if ref and ref.address else "" + return format_address_output(obj.references.first()) def get_images(self, obj): request = self.context.get('request') @@ -1226,8 +1244,7 @@ class HadisCorrectionDetailSerializer(serializers.ModelSerializer): return {"id": obj.hadis.id, "number": obj.hadis.number, "slug": obj.hadis.slug} def get_address(self, obj): - ref = obj.references.first() - return ref.address if ref and ref.address else "" + return format_address_output(obj.references.first()) def get_images(self, obj): request = self.context.get('request') @@ -1264,8 +1281,7 @@ class HadisInterpretationDetailSerializer(serializers.ModelSerializer): } def get_address(self, obj): - ref = obj.references.first() - return ref.address if ref and ref.address else "" + return format_address_output(obj.references.first()) def get_images(self, obj): request = self.context.get('request') diff --git a/apps/hadis/serializers/serializers_admin.py b/apps/hadis/serializers/serializers_admin.py index 66fcfca..6f14176 100644 --- a/apps/hadis/serializers/serializers_admin.py +++ b/apps/hadis/serializers/serializers_admin.py @@ -437,7 +437,11 @@ def save_relation_reference_data(instance, validated_data, request=None, is_corr if book_reference is not None: ref.book_reference = book_reference if address is not None: - ref.address = address + if isinstance(address, (list, dict)): + import json + ref.address = json.dumps(address, ensure_ascii=False) + else: + ref.address = str(address) ref.save() if delete_image_ids: @@ -465,11 +469,10 @@ class AdminHadisCorrectionSerializer(serializers.ModelSerializer): write_only=True, allow_null=True ) - address = serializers.CharField( + address = serializers.JSONField( required=False, write_only=True, - allow_null=True, - allow_blank=True + allow_null=True ) delete_image_ids = serializers.ListField( child=serializers.IntegerField(), @@ -501,7 +504,7 @@ class AdminHadisCorrectionSerializer(serializers.ModelSerializer): def to_internal_value(self, data): import json data = safe_copy_data(data) - for json_field in ["title", "translation", "links"]: + for json_field in ["title", "translation", "links", "address"]: val = data.get(json_field) if isinstance(val, str): try: @@ -526,11 +529,20 @@ class AdminHadisCorrectionSerializer(serializers.ModelSerializer): return super().to_internal_value(data) def to_representation(self, instance): + import json ret = super().to_representation(instance) refs = list(instance.references.all()) ref = refs[0] if refs else None ret["book_reference"] = ref.book_reference_id if ref else None - ret["address"] = ref.address if ref else "" + + addr_val = ref.address if ref and ref.address else "" + if isinstance(addr_val, str) and (addr_val.strip().startswith("[") or addr_val.strip().startswith("{")): + try: + ret["address"] = json.loads(addr_val) + except (ValueError, TypeError): + ret["address"] = addr_val + else: + ret["address"] = addr_val request = self.context.get("request") images = list(ref.images.all()) if ref else [] @@ -586,11 +598,10 @@ class AdminHadisInterpretationSerializer(serializers.ModelSerializer): write_only=True, allow_null=True ) - address = serializers.CharField( + address = serializers.JSONField( required=False, write_only=True, - allow_null=True, - allow_blank=True + allow_null=True ) delete_image_ids = serializers.ListField( child=serializers.IntegerField(), @@ -620,7 +631,7 @@ class AdminHadisInterpretationSerializer(serializers.ModelSerializer): def to_internal_value(self, data): import json data = safe_copy_data(data) - for json_field in ["title", "translation", "links"]: + for json_field in ["title", "translation", "links", "address"]: val = data.get(json_field) if isinstance(val, str): try: @@ -645,11 +656,20 @@ class AdminHadisInterpretationSerializer(serializers.ModelSerializer): return super().to_internal_value(data) def to_representation(self, instance): + import json ret = super().to_representation(instance) refs = list(instance.references.all()) ref = refs[0] if refs else None ret["book_reference"] = ref.book_reference_id if ref else None - ret["address"] = ref.address if ref else "" + + addr_val = ref.address if ref and ref.address else "" + if isinstance(addr_val, str) and (addr_val.strip().startswith("[") or addr_val.strip().startswith("{")): + try: + ret["address"] = json.loads(addr_val) + except (ValueError, TypeError): + ret["address"] = addr_val + else: + ret["address"] = addr_val request = self.context.get("request") images = list(ref.images.all()) if ref else [] @@ -1642,11 +1662,10 @@ class AdminTransmitterOriginalTextSerializer(serializers.ModelSerializer): write_only=True, allow_null=True ) - address = serializers.CharField( + address = serializers.JSONField( required=False, write_only=True, - allow_null=True, - allow_blank=True + allow_null=True ) delete_image_ids = serializers.ListField( child=serializers.IntegerField(), @@ -1674,7 +1693,7 @@ class AdminTransmitterOriginalTextSerializer(serializers.ModelSerializer): def to_internal_value(self, data): import json data = safe_copy_data(data) - for json_field in ["title", "text", "translation"]: + for json_field in ["title", "text", "translation", "address"]: val = data.get(json_field) if isinstance(val, str): try: @@ -1699,10 +1718,19 @@ class AdminTransmitterOriginalTextSerializer(serializers.ModelSerializer): return super().to_internal_value(data) def to_representation(self, instance): + import json ret = super().to_representation(instance) ref = instance.references.first() ret["book_reference"] = ref.book_reference_id if ref else None - ret["address"] = ref.address if ref else "" + + addr_val = ref.address if ref and ref.address else "" + if isinstance(addr_val, str) and (addr_val.strip().startswith("[") or addr_val.strip().startswith("{")): + try: + ret["address"] = json.loads(addr_val) + except (ValueError, TypeError): + ret["address"] = addr_val + else: + ret["address"] = addr_val request = self.context.get("request") ret["images"] = [