Browse Source

hadis multilanguage fields refactor

hadis data synced with projects language map with migrate_json_key script command

all the views , serializers , admin methods and models updated with this data schema update .
master
Mohsen Taba 14 hours ago
parent
commit
6c13b951c0
  1. 139
      apps/hadis/admin/category.py
  2. 614
      apps/hadis/admin/hadis.py
  3. 349
      apps/hadis/admin/reference.py
  4. 422
      apps/hadis/admin/transmitter.py
  5. 69
      apps/hadis/management/commands/migrate_json_keys.py
  6. 22
      apps/hadis/models/category.py
  7. 46
      apps/hadis/models/hadis.py
  8. 44
      apps/hadis/models/reference.py
  9. 60
      apps/hadis/models/transmitter.py
  10. 16
      apps/hadis/serializers/category.py
  11. 6
      apps/hadis/views/category.py

139
apps/hadis/admin/category.py

@ -5,7 +5,8 @@ from django.utils.html import format_html
from unfold.admin import ModelAdmin
from unfold.decorators import display, action
from mptt.admin import DraggableMPTTAdmin
from utils.json_editor_field import JsonEditorWidget
from unfold.widgets import UnfoldAdminTextInputWidget, UnfoldAdminTextareaWidget, UnfoldAdminExpandableTextareaWidget
from utils.multilang_json_widget import MultiLanguageJSONWidget
import json
from utils.admin import dovoodi_admin_site
@ -19,71 +20,11 @@ class HadisSectAdminForm(forms.ModelForm):
class Meta:
model = HadisSect
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for description JSON field
description_schema = {
"type": "array",
"title": "Descriptions",
"items": {
"type": "object",
"title": "Description",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Description Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
self.fields['description'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(description_schema),
'title': 'Descriptions'
})
class HadisCategoryAdminForm(forms.ModelForm):
"""Custom form for HadisCategory with JSON editor widgets"""
@ -91,71 +32,11 @@ class HadisCategoryAdminForm(forms.ModelForm):
class Meta:
model = HadisCategory
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for description JSON field
description_schema = {
"type": "array",
"title": "Descriptions",
"items": {
"type": "object",
"title": "Description",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Description Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
self.fields['description'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(description_schema),
'title': 'Descriptions'
})
class HadisSectAdmin(ModelAdmin):
"""Admin for HadisSect model"""
@ -174,7 +55,7 @@ class HadisSectAdmin(ModelAdmin):
def display_title(self, obj):
"""Extracts text from the title JSON list"""
try:
return obj.title[0]['text']
return obj.title[0]['title']
except (IndexError, KeyError, TypeError, AttributeError):
return "No Title"
@ -205,7 +86,7 @@ class HadisCategoryAdmin(ModelAdmin):
"""Display indented title for tree structure using JSON text"""
try:
# Extract text from the first element of the title list
title_text = instance.title[0]['text']
title_text = instance.title[0]['title']
except (IndexError, KeyError, TypeError, AttributeError):
title_text = "No Title"

614
apps/hadis/admin/hadis.py

@ -4,10 +4,12 @@ from django.utils.translation import gettext_lazy as _
from unfold.admin import ModelAdmin, TabularInline
from unfold.contrib.forms.widgets import WysiwygWidget
from unfold.decorators import display, action
from unfold.widgets import UnfoldAdminTextInputWidget, UnfoldAdminTextareaWidget
from utils.multilang_json_widget import MultiLanguageJSONWidget, MultiLanguageAddressWidget, LinksJSONWidget
from utils.json_editor_field import JsonEditorWidget
import json
from utils.admin import dovoodi_admin_site,dovoodi_admin_site
from utils.admin import dovoodi_admin_site
from ..models import (
Hadis, HadisReference, HadisTag, HadisStatus, ReferenceImage,
HadisCollection, HadisInCollection, HadisCorrection
@ -22,189 +24,18 @@ class HadisAdminForm(forms.ModelForm):
model = Hadis
fields = '__all__'
widgets = {
'explanation': WysiwygWidget(),
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'title_narrator': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
'translation': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
'address': MultiLanguageAddressWidget(),
'links': LinksJSONWidget(),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for translation JSON field
translation_schema = {
"type": "array",
"title": "Translations",
"items": {
"type": "object",
"title": "Translation",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu"]
}
},
"text": { # <‑‑ use text, not title
"type": "string",
"title": "Translation Text"
}
},
"required": ["language_code", "text"] # <‑‑ update required key
}
}
# Schema for links JSON field (array of objects with title and link)
links_schema = {
"type": "array",
"title": "Links",
"items": {
"type": "object",
"title": "Link",
"properties": {
"title": {
"type": "string",
"title": "Link Title"
},
"link": {
"type": "string",
"title": "URL",
"format": "uri"
}
},
"required": ["title", "link"]
}
}
# Schema for title_narrator JSON field
title_narrator_schema = {
"type": "array",
"title": "Title Narrators",
"items": {
"type": "object",
"title": "Title Narrator",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Narrator Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for description JSON field
description_schema = {
"type": "array",
"title": "Descriptions",
"items": {
"type": "object",
"title": "Description",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Description Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for hadis_status_text JSON field
hadis_status_text_schema = {
"type": "array",
"title": "Status Texts",
"items": {
"type": "object",
"title": "Status Text",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Status Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for address JSON field (text is an array of strings)
address_schema = {
"type": "array",
"title": "Addresses",
"items": {
"type": "object",
"title": "Address",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "array",
"title": "Address Parts",
"items": {
"type": "string",
"title": "Address Part"
}
}
},
"required": ["language_code", "text"]
}
}
# Schema for explanation JSON field (text is an array of objects with title and detail)
# Schema for explanation JSON field (title is an array of objects with title and detail)
explanation_schema = {
"type": "array",
"title": "Explanations",
@ -220,7 +51,7 @@ class HadisAdminForm(forms.ModelForm):
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"title": {
"type": "array",
"title": "Explanation Items",
"items": {
@ -241,111 +72,15 @@ class HadisAdminForm(forms.ModelForm):
}
}
},
"required": ["language_code", "text"]
"required": ["language_code", "title"]
}
}
# Schema for explanations JSON field (array of objects with title and description)
# explanations_schema = {
# "type": "array",
# "title": "Explanations",
# "items": {
# "type": "object",
# "title": "Explanation",
# "properties": {
# "language_code": {
# "type": "string",
# "title": "Language Code",
# "enum": ["en", "fa", "ar", "ur", "ru"],
# "options": {
# "enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
# }
# },
# "title": {
# "type": "string",
# "title": "Title"
# },
# "description": {
# "type": "string",
# "title": "Description"
# }
# },
# "required": ["language_code", "title", "description"]
# }
# }
# Schema for address_details JSON field (array of objects with text and priority)
# address_details_schema = {
# "type": "array",
# "title": "Address Details",
# "items": {
# "type": "object",
# "title": "Address Detail",
# "properties": {
# "text": {
# "type": "string",
# "title": "Address Text"
# },
# "priority": {
# "type": "integer",
# "title": "Priority",
# "minimum": 0
# }
# },
# "required": ["text", "priority"]
# }
# }
# Apply JSON editor widgets
self.fields['translation'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(translation_schema),
'title': 'Translations'
})
self.fields['links'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(links_schema),
'title': 'Links'
})
self.fields['title_narrator'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_narrator_schema),
'title': 'Title Narrators'
})
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
self.fields['description'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(description_schema),
'title': 'Descriptions'
})
# self.fields['hadis_status_text'].widget = JsonEditorWidget(attrs={
# 'schema': json.dumps(hadis_status_text_schema),
# 'title': 'Status Texts'
# })
self.fields['address'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(address_schema),
'title': 'Addresses'
})
self.fields['explanation'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(explanation_schema),
'title': 'Explanations'
})
# self.fields['explanations'].widget = JsonEditorWidget(attrs={
# 'schema': json.dumps(explanations_schema),
# self.fields['explanation'].widget = JsonEditorWidget(attrs={
# 'schema': json.dumps(explanation_schema),
# 'title': 'Explanations'
# })
# self.fields['address_details'].widget = JsonEditorWidget(attrs={
# 'schema': json.dumps(address_details_schema),
# 'title': 'Address Details'
# })
# Custom Forms for JSON Fields
@ -355,71 +90,11 @@ class HadisCollectionAdminForm(forms.ModelForm):
class Meta:
model = HadisCollection
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for summary JSON field
summary_schema = {
"type": "array",
"title": "Summaries",
"items": {
"type": "object",
"title": "Summary",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Summary Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'summary': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
self.fields['summary'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(summary_schema),
'title': 'Summaries'
})
class HadisTagAdminForm(forms.ModelForm):
"""Custom form for HadisTag with JSON editor widgets"""
@ -427,41 +102,10 @@ class HadisTagAdminForm(forms.ModelForm):
class Meta:
model = HadisTag
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
class HadisStatusAdminForm(forms.ModelForm):
"""Custom form for HadisStatus with JSON editor widgets"""
@ -469,71 +113,11 @@ class HadisStatusAdminForm(forms.ModelForm):
class Meta:
model = HadisStatus
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for description JSON field
description_schema = {
"type": "array",
"title": "Descriptions",
"items": {
"type": "object",
"title": "Description",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Description Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
self.fields['description'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(description_schema),
'title': 'Descriptions'
})
class HadisReferenceAdminForm(forms.ModelForm):
"""Custom form for HadisReference with JSON editor widgets"""
@ -541,41 +125,10 @@ class HadisReferenceAdminForm(forms.ModelForm):
class Meta:
model = HadisReference
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for description JSON field
description_schema = {
"type": "array",
"title": "Descriptions",
"items": {
"type": "object",
"title": "Description",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Description Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
}
# Apply JSON editor widgets
self.fields['description'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(description_schema),
'title': 'Descriptions'
})
# Inline Admin Classes
class ReferenceImageInline(TabularInline):
@ -619,11 +172,11 @@ class HadisTagAdmin(ModelAdmin):
return self._extract_first_text(obj.title)
def _extract_first_text(self, json_data):
"""Helper to safely extract the first 'text' from a JSON list"""
"""Helper to safely extract the first 'title' from a JSON list"""
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first_item = json_data[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return first_item.get('title', '-')
return '-'
@ -651,11 +204,11 @@ class HadisStatusAdmin(ModelAdmin):
return self._extract_first_text(obj.description)
def _extract_first_text(self, json_data):
"""Helper to safely extract the first 'text' from a JSON list"""
"""Helper to safely extract the first 'title' from a JSON list"""
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first_item = json_data[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return first_item.get('title', '-')
return '-'
@ -675,7 +228,7 @@ class HadisAdmin(ModelAdmin):
'fields': ('category', 'number', 'title', 'title_narrator', 'status', 'slug')
}),
(_('Content'), {
'fields': ('text', 'translation', 'explanation','description')
'fields': ('text', 'translation','description')
}),
(_('Status & Classification'), {
'fields': ('hadis_status','tags')
@ -695,11 +248,11 @@ class HadisAdmin(ModelAdmin):
return self._extract_first_text(obj.title)
def _extract_first_text(self, json_data):
"""Helper to safely extract the first 'text' from a JSON list"""
"""Helper to safely extract the first 'title' from a JSON list"""
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first_item = json_data[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return first_item.get('title', '-')
return '-'
@ -770,11 +323,11 @@ class HadisCollectionAdmin(ModelAdmin):
return self._extract_first_text(obj.title)
def _extract_first_text(self, json_data):
"""Helper to safely extract the first 'text' from a JSON list"""
"""Helper to safely extract the first 'title' from a JSON list"""
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first_item = json_data[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return first_item.get('title', '-')
return '-'
@display(description=_("Collection"), header=True)
@ -824,101 +377,12 @@ class HadisCorrectionAdminForm(forms.ModelForm):
class Meta:
model = HadisCorrection
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for description JSON field
description_schema = {
"type": "array",
"title": "Descriptions",
"items": {
"type": "object",
"title": "Description",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Description Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for translation JSON field
translation_schema = {
"type": "array",
"title": "Translations",
"items": {
"type": "object",
"title": "Translation",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Translation Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
'translation': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
self.fields['description'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(description_schema),
'title': 'Descriptions'
})
self.fields['translation'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(translation_schema),
'title': 'Translations'
})
class HadisCorrectionAdmin(ModelAdmin):
"""Admin for HadisCorrection model"""
@ -951,11 +415,11 @@ class HadisCorrectionAdmin(ModelAdmin):
return self._extract_first_text(obj.title)
def _extract_first_text(self, json_data):
"""Helper to safely extract the first 'text' from a JSON list"""
"""Helper to safely extract the first 'title' from a JSON list"""
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first_item = json_data[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return first_item.get('title', '-')
return '-'

349
apps/hadis/admin/reference.py

@ -3,7 +3,8 @@ from django import forms
from django.utils.translation import gettext_lazy as _
from unfold.admin import ModelAdmin, TabularInline
from unfold.decorators import display
from utils.json_editor_field import JsonEditorWidget
from unfold.widgets import UnfoldAdminTextInputWidget, UnfoldAdminTextareaWidget, UnfoldAdminExpandableTextareaWidget
from utils.multilang_json_widget import MultiLanguageJSONWidget
import json
# Import your custom admin site
@ -29,131 +30,13 @@ class BookReferenceAdminForm(forms.ModelForm):
class Meta:
model = BookReference
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for description JSON field
description_schema = {
"type": "array",
"title": "Descriptions",
"items": {
"type": "object",
"title": "Description",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Description Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for language JSON field
language_schema = {
"type": "array",
"title": "Languages",
"items": {
"type": "object",
"title": "Language",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Language Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for publisher JSON field
publisher_schema = {
"type": "array",
"title": "Publishers",
"items": {
"type": "object",
"title": "Publisher",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Publisher Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
'language': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'publisher': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
self.fields['description'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(description_schema),
'title': 'Descriptions'
})
self.fields['language'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(language_schema),
'title': 'Languages'
})
self.fields['publisher'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(publisher_schema),
'title': 'Publishers'
})
class BookAttributeAdminForm(forms.ModelForm):
"""Custom form for BookAttribute with JSON editor widgets"""
@ -161,71 +44,11 @@ class BookAttributeAdminForm(forms.ModelForm):
class Meta:
model = BookAttribute
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'value': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
}
# Schema for value JSON field
value_schema = {
"type": "array",
"title": "Values",
"items": {
"type": "object",
"title": "Value",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Value Text"
}
},
"required": ["language_code", "text"]
}
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
self.fields['value'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(value_schema),
'title': 'Values'
})
class BookAuthorAdminForm(forms.ModelForm):
"""Custom form for BookAuthor with JSON editor widgets"""
@ -233,41 +56,10 @@ class BookAuthorAdminForm(forms.ModelForm):
class Meta:
model = BookAuthor
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for name JSON field
name_schema = {
"type": "array",
"title": "Names",
"items": {
"type": "object",
"title": "Name",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Name Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'name': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
}
# Apply JSON editor widgets
self.fields['name'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(name_schema),
'title': 'Names'
})
class BookReferenceImageAdminForm(forms.ModelForm):
"""Custom form for BookReferenceImage with JSON editor widgets"""
@ -275,41 +67,10 @@ class BookReferenceImageAdminForm(forms.ModelForm):
class Meta:
model = BookReferenceImage
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for description JSON field
description_schema = {
"type": "array",
"title": "Descriptions",
"items": {
"type": "object",
"title": "Description",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Description Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
}
# Apply JSON editor widgets
self.fields['description'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(description_schema),
'title': 'Descriptions'
})
class BookSubjectAreaAdminForm(forms.ModelForm):
"""Custom form for BookSubjectArea with JSON editor widgets"""
@ -317,41 +78,10 @@ class BookSubjectAreaAdminForm(forms.ModelForm):
class Meta:
model = BookSubjectArea
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
class BookTypeAdminForm(forms.ModelForm):
"""Custom form for BookType with JSON editor widgets"""
@ -359,41 +89,10 @@ class BookTypeAdminForm(forms.ModelForm):
class Meta:
model = BookType
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
# -----------------------------------------------------------------------------
# 1. Inlines
@ -476,11 +175,11 @@ class BookReferenceAdmin(ModelAdmin):
return self._extract_first_text(obj.publisher)
def _extract_first_text(self, json_data):
"""Helper to safely extract the first 'text' from a JSON list"""
"""Helper to safely extract the first 'title' from a JSON list"""
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first_item = json_data[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return first_item.get('title', '-')
return '-'
@ -520,7 +219,7 @@ class BookAuthorAdmin(ModelAdmin):
if obj.name and isinstance(obj.name, list) and len(obj.name) > 0:
first = obj.name[0]
if isinstance(first, dict):
return first.get('text', '-')
return first.get('title', '-')
return '-'
class BookReferenceImageAdmin(ModelAdmin):
@ -534,10 +233,10 @@ class BookReferenceImageAdmin(ModelAdmin):
list_select_related = ("book_reference",)
def display_name(self, obj):
# Implements: f"{self.book_reference.title[0]['text']} - Image {self.order}"
# Implements: f"{self.book_reference.title[0]['title']} - Image {self.order}"
try:
# We use safe navigation to prevent admin crashes if data is missing
book_title = obj.book_reference.title[0]['text']
book_title = obj.book_reference.title[0]['title']
return f"{book_title} - Image {obj.order}"
except (AttributeError, IndexError, KeyError, TypeError):
# Fallback if the title structure isn't exactly as expected
@ -574,7 +273,7 @@ class BookAttributeAdmin(ModelAdmin):
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first = json_data[0]
if isinstance(first, dict):
return first.get('text', '-')
return first.get('title', '-')
return '-'

422
apps/hadis/admin/transmitter.py

@ -4,7 +4,8 @@ from django.utils.translation import gettext_lazy as _
from unfold.admin import ModelAdmin, TabularInline
from unfold.decorators import display, action
from unfold.contrib.forms.widgets import WysiwygWidget
from utils.json_editor_field import JsonEditorWidget
from unfold.widgets import UnfoldAdminTextInputWidget, UnfoldAdminTextareaWidget, UnfoldAdminExpandableTextareaWidget
from utils.multilang_json_widget import MultiLanguageJSONWidget
import json
from utils.admin import dovoodi_admin_site
@ -20,9 +21,6 @@ class HadisTransmitterInline(TabularInline):
fields = ('hadis', 'order')
# (TransmitterOpinionInline and TransmitterOriginalTextInline moved after their forms)
# Custom Forms for JSON Fields
class TransmittersAdminForm(forms.ModelForm):
"""Custom form for Transmitters with JSON editor widgets"""
@ -30,89 +28,16 @@ class TransmittersAdminForm(forms.ModelForm):
class Meta:
model = Transmitters
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Helper function to create standard language schema
def create_language_schema(title_name, text_title):
return {
"type": "array",
"title": title_name,
"items": {
"type": "object",
"title": title_name[:-1] if title_name.endswith('s') else title_name,
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": text_title
}
},
"required": ["language_code", "text"]
}
}
# Create schemas for all JSON fields
full_name_schema = create_language_schema("Full Names", "Full Name Text")
kunya_schema = create_language_schema("Kunyas", "Kunya Text")
known_as_schema = create_language_schema("Known As", "Known As Text")
nickname_schema = create_language_schema("Nicknames", "Nickname Text")
origin_schema = create_language_schema("Origins", "Origin Text")
lived_in_schema = create_language_schema("Lived In", "Lived In Text")
died_in_schema = create_language_schema("Died In", "Died In Text")
description_schema = create_language_schema("Descriptions", "Description Text")
# Apply JSON editor widgets
self.fields['full_name'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(full_name_schema),
'title': 'Full Names'
})
self.fields['kunya'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(kunya_schema),
'title': 'Kunyas'
})
self.fields['known_as'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(known_as_schema),
'title': 'Known As'
})
self.fields['nickname'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(nickname_schema),
'title': 'Nicknames'
})
self.fields['origin'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(origin_schema),
'title': 'Origins'
})
self.fields['lived_in'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(lived_in_schema),
'title': 'Lived In'
})
self.fields['died_in'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(died_in_schema),
'title': 'Died In'
})
self.fields['description'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(description_schema),
'title': 'Descriptions'
})
# (Admins moved down to avoid NameError)
widgets = {
'full_name': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'kunya': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'known_as': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'nickname': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'origin': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'lived_in': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'died_in': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
}
# Custom Forms for JSON Fields
@ -122,71 +47,11 @@ class NarratorLayerAdminForm(forms.ModelForm):
class Meta:
model = NarratorLayer
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for name JSON field
name_schema = {
"type": "array",
"title": "Names",
"items": {
"type": "object",
"title": "Name",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Name Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for description JSON field
description_schema = {
"type": "array",
"title": "Descriptions",
"items": {
"type": "object",
"title": "Description",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Description Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'name': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
}
# Apply JSON editor widgets
self.fields['name'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(name_schema),
'title': 'Names'
})
self.fields['description'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(description_schema),
'title': 'Descriptions'
})
class TransmitterReliabilityAdminForm(forms.ModelForm):
"""Custom form for TransmitterReliability with JSON editor widgets"""
@ -194,41 +59,10 @@ class TransmitterReliabilityAdminForm(forms.ModelForm):
class Meta:
model = TransmitterReliability
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
class OpinionStatusAdminForm(forms.ModelForm):
"""Custom form for OpinionStatus with JSON editor widgets"""
@ -236,41 +70,10 @@ class OpinionStatusAdminForm(forms.ModelForm):
class Meta:
model = OpinionStatus
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
class TransmitterOpinionAdminForm(forms.ModelForm):
"""Custom form for TransmitterOpinion with JSON editor widgets"""
@ -278,71 +81,11 @@ class TransmitterOpinionAdminForm(forms.ModelForm):
class Meta:
model = TransmitterOpinion
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for scholar_name JSON field
scholar_name_schema = {
"type": "array",
"title": "Scholar Names",
"items": {
"type": "object",
"title": "Scholar Name",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Scholar Name Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for opinion_text JSON field
opinion_text_schema = {
"type": "array",
"title": "Opinion Texts",
"items": {
"type": "object",
"title": "Opinion Text",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Opinion Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'scholar_name': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'opinion_text': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
}
# Apply JSON editor widgets
self.fields['scholar_name'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(scholar_name_schema),
'title': 'Scholar Names'
})
self.fields['opinion_text'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(opinion_text_schema),
'title': 'Opinion Texts'
})
class TransmitterOriginalTextAdminForm(forms.ModelForm):
"""Custom form for TransmitterOriginalText with JSON editor widgets"""
@ -350,101 +93,12 @@ class TransmitterOriginalTextAdminForm(forms.ModelForm):
class Meta:
model = TransmitterOriginalText
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
widgets = {
'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget),
'text': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
'translation': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget),
}
# Schema for text JSON field
text_schema = {
"type": "array",
"title": "Texts",
"items": {
"type": "object",
"title": "Text",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Text Content"
}
},
"required": ["language_code", "text"]
}
}
# Schema for translation JSON field
translation_schema = {
"type": "array",
"title": "Translations",
"items": {
"type": "object",
"title": "Translation",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Translation Text"
}
},
"required": ["language_code", "text"]
}
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
self.fields['text'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(text_schema),
'title': 'Texts'
})
self.fields['translation'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(translation_schema),
'title': 'Translations'
})
class TransmitterOpinionInline(TabularInline):
"""Inline for TransmitterOpinion in Transmitters admin"""
@ -490,13 +144,13 @@ class TransmittersAdmin(ModelAdmin):
@display(description=_('Full Name'), ordering='full_name')
def get_full_name_display(self, obj):
"""
Parses the JSON full_name and returns the first item's text.
Parses the JSON full_name and returns the first item's title.
"""
if obj.full_name and isinstance(obj.full_name, list) and len(obj.full_name) > 0:
# Safely get the first item
first_item = obj.full_name[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return first_item.get('title', '-')
return '-'
@display(description=_("Transmitter"), header=True)
@ -552,11 +206,11 @@ class NarratorLayerAdmin(ModelAdmin):
return self._extract_first_text(obj.name)
def _extract_first_text(self, json_data):
"""Helper to safely extract the first 'text' from a JSON list"""
"""Helper to safely extract the first 'title' from a JSON list"""
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first_item = json_data[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return first_item.get('title', '-')
return '-'
@ -579,11 +233,11 @@ class TransmitterReliabilityAdmin(ModelAdmin):
return self._extract_first_text(obj.title)
def _extract_first_text(self, json_data):
"""Helper to safely extract the first 'text' from a JSON list"""
"""Helper to safely extract the first 'title' from a JSON list"""
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first_item = json_data[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return first_item.get('title', '-')
return '-'
@ -606,11 +260,11 @@ class OpinionStatusAdmin(ModelAdmin):
return self._extract_first_text(obj.title)
def _extract_first_text(self, json_data):
"""Helper to safely extract the first 'text' from a JSON list"""
"""Helper to safely extract the first 'title' from a JSON list"""
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first_item = json_data[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return first_item.get('title', '-')
return '-'
@ -642,11 +296,11 @@ class TransmitterOpinionAdmin(ModelAdmin):
return self._extract_first_text(obj.scholar_name)
def _extract_first_text(self, json_data):
"""Helper to safely extract the first 'text' from a JSON list"""
"""Helper to safely extract the first 'title' from a JSON list"""
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first_item = json_data[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return first_item.get('title', '-')
return '-'
@ -679,11 +333,11 @@ class TransmitterOriginalTextAdmin(ModelAdmin):
return self._extract_first_text(obj.title)
def _extract_first_text(self, json_data):
"""Helper to safely extract the first 'text' from a JSON list"""
"""Helper to safely extract the first 'title' from a JSON list"""
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first_item = json_data[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return first_item.get('title', '-')
return '-'

69
apps/hadis/management/commands/migrate_json_keys.py

@ -0,0 +1,69 @@
from django.core.management.base import BaseCommand
from django.db import transaction
from django.apps import apps
from django.db import models as django_models
class Command(BaseCommand):
help = "Rename 'text' key to 'title' in all multi-language JSON fields across Hadis app models."
@transaction.atomic
def handle(self, *args, **options):
hadis_app = apps.get_app_config('hadis')
models = hadis_app.get_models()
self.stdout.write("Starting key migration in JSON fields...")
for model in models:
json_fields = [
f.name for f in model._meta.get_fields()
if isinstance(f, django_models.JSONField)
]
if not json_fields:
continue
self.stdout.write(f"Checking model {model.__name__} for fields: {json_fields}")
queryset = model.objects.all()
for obj in queryset:
changed = False
for field in json_fields:
value = getattr(obj, field)
if not isinstance(value, list):
continue
new_list = []
field_changed = False
for item in value:
if isinstance(item, dict):
# Check if this item follows the multi-language pattern
# lang_key can be 'language_code', 'lang', or 'code'
lang_val = item.get("language_code") or item.get("lang") or item.get("code")
# text_val can be 'text' or 'title'
text_val = item.get("text")
if lang_val and text_val is not None:
# We found a multi-language item with a 'text' key
new_item = {
"language_code": str(lang_val),
"title": text_val
}
# Copy any other keys
for k, v in item.items():
if k not in ["language_code", "lang", "code", "text", "title"]:
new_item[k] = v
new_list.append(new_item)
field_changed = True
else:
new_list.append(item)
else:
new_list.append(item)
if field_changed:
setattr(obj, field, new_list)
changed = True
if changed:
obj.save()
self.stdout.write(f" Updated keys in {model.__name__} ID: {obj.id}")
self.stdout.write(self.style.SUCCESS("JSON key migration completed!"))

22
apps/hadis/models/category.py

@ -18,7 +18,7 @@ class HadisSect(models.Model):
order = models.IntegerField(default=0, verbose_name=_('order'))
def __str__(self):
title = self.title[0]['text'] if self.title else "Untitled Sect"
title = self.title[0].get('title') or self.title[0].get('text', '') if self.title else "Untitled Sect"
return f"{self.sect_type}: {title}"
def get_title(self,lang):
@ -31,11 +31,11 @@ class HadisSect(models.Model):
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
def get_description(self,lang):
@ -48,11 +48,11 @@ class HadisSect(models.Model):
for tr in self.description:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.description:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
@ -100,7 +100,7 @@ class HadisCategory(MPTTModel):
if self.title and isinstance(self.title, list) and len(self.title) > 0:
first_item = self.title[0]
if isinstance(first_item, dict):
title_text = first_item.get('text', '').strip()
title_text = (first_item.get('title') or first_item.get('text') or '').strip()
if title_text:
base_slug = slugify(title_text, allow_unicode=True)
slug = base_slug
@ -175,7 +175,7 @@ class HadisCategory(MPTTModel):
ordering = ('order',)
def __str__(self):
title = self.title[0]['text'] if self.title else "Untitled Category"
title = self.title[0].get('title') or self.title[0].get('text', '') if self.title else "Untitled Category"
return f"{self.sect.sect_type}: {self.source_type} - {title}"
def get_title(self,lang):
@ -188,11 +188,11 @@ class HadisCategory(MPTTModel):
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
def get_description(self,lang):
@ -205,11 +205,11 @@ class HadisCategory(MPTTModel):
for tr in self.description:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.description:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None

46
apps/hadis/models/hadis.py

@ -79,7 +79,7 @@ class HadisCollection(models.Model):
super().save(*args, **kwargs)
def __str__(self):
return self.title[0]['text'] if self.title else "Untitled Collection"
return self.title[0]['title'] if self.title else "Untitled Collection"
def get_title(self,lang):
"""
@ -91,11 +91,11 @@ class HadisCollection(models.Model):
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title', '')
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title', '')
return None
def get_summary(self,lang):
@ -108,11 +108,11 @@ class HadisCollection(models.Model):
for tr in self.summary:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title', '')
for tr in self.summary:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title', '')
return None
class Meta:
@ -144,7 +144,7 @@ class HadisTag(models.Model):
updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at'))
def __str__(self):
return self.title[0]['text'] if self.title else "Untagged"
return self.title[0]['title'] if self.title else "Untagged"
def get_title(self,lang):
"""
@ -156,11 +156,11 @@ class HadisTag(models.Model):
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title', '')
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title', '')
return None
@ -232,7 +232,7 @@ class HadisStatus(ColorPaletteMixin,models.Model):
super().save(*args, **kwargs)
def __str__(self):
return self.title[0]['text'] if self.title else str(self.id)
return self.title[0]['title'] if self.title else str(self.id)
def get_title(self,lang):
"""
@ -248,7 +248,7 @@ class HadisStatus(ColorPaletteMixin,models.Model):
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
class Meta:
@ -288,7 +288,7 @@ class Hadis(models.Model):
embedded_in = models.JSONField(default=list, blank=True)
def __str__(self):
title = self.title[0]['text'] if self.title else f"Hadis {self.number}"
title = self.title[0].get('title') or self.title[0].get('text', '') if self.title else f"Hadis {self.number}"
return f"{self.number} - {title}"
def save(self, *args, **kwargs):
@ -300,7 +300,7 @@ class Hadis(models.Model):
if self.title and isinstance(self.title, list) and len(self.title) > 0:
first_item = self.title[0]
if isinstance(first_item, dict):
title_text = first_item.get("text")
title_text = first_item.get("title") or first_item.get("text")
# 2. If we found text, use smart slug
if title_text:
@ -355,18 +355,18 @@ class Hadis(models.Model):
# 1) exact language
for item in value:
if isinstance(item, dict) and item.get("language_code") == lang:
return item.get("text", "")
return item.get("title") or item.get("text") or ""
# 2) fallback language
if fallback and fallback != lang:
for item in value:
if isinstance(item, dict) and item.get("language_code") == fallback:
return item.get("text", "")
return item.get("title") or item.get("text") or ""
# 3) first available
item = value[0]
print(item)
return item.get("text", "") if isinstance(item, dict) else None
return item.get("title") or item.get("text") if isinstance(item, dict) else None
def get_translation(self, lang):
return self._get_json_field("translation" , lang)
@ -448,11 +448,11 @@ class HadisReference(models.Model):
for tr in self.description:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.description:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
def __str__(self):
@ -507,7 +507,7 @@ class HadisCorrection(models.Model):
ordering = ("-created_at",)
def __str__(self):
title = self.title[0]['text'] if self.title else "No Title"
title = self.title[0].get('title') or self.title[0].get('text', '') if self.title else "No Title"
return f"{self.hadis.number} - {title}"
def save(self, *args, **kwargs):
@ -517,7 +517,7 @@ class HadisCorrection(models.Model):
if isinstance(self.title, list) and len(self.title) > 0:
first_item = self.title[0]
if isinstance(first_item, dict):
title_text = first_item.get("text")
title_text = first_item.get("title") or first_item.get("text")
if title_text:
self.slug = generate_smart_slug(
@ -549,17 +549,17 @@ class HadisCorrection(models.Model):
def get_title(self, lang):
if not self.title or not isinstance(self.title, list): return None
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == lang: return tr.get('text', '')
if isinstance(tr, dict) and tr.get('language_code') == lang: return tr.get('title') or tr.get('text') or ''
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == 'en': return tr.get('text', '')
if isinstance(tr, dict) and tr.get('language_code') == 'en': return tr.get('title') or tr.get('text') or ''
return None
def get_translation(self, lang):
if not self.translation or not isinstance(self.translation, list): return None
for tr in self.translation:
if isinstance(tr, dict) and tr.get('language_code') == lang: return tr.get('text', '')
if isinstance(tr, dict) and tr.get('language_code') == lang: return tr.get('title') or tr.get('text') or ''
for tr in self.translation:
if isinstance(tr, dict) and tr.get('language_code') == 'en': return tr.get('text', '')
if isinstance(tr, dict) and tr.get('language_code') == 'en': return tr.get('title') or tr.get('text') or ''
return None

44
apps/hadis/models/reference.py

@ -10,7 +10,7 @@ class BookSubjectArea(models.Model):
updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at'))
def __str__(self):
return self.title[0]['text'] if self.title else str(self.id)
return self.title[0].get('title') or self.title[0].get('text', '') if self.title else str(self.id)
def get_title(self,lang):
"""
@ -22,11 +22,11 @@ class BookSubjectArea(models.Model):
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
@ -36,7 +36,7 @@ class BookType(models.Model):
updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at'))
def __str__(self):
return self.title[0]['text'] if self.title else str(self.id)
return self.title[0].get('title') or self.title[0].get('text', '') if self.title else str(self.id)
def get_title(self,lang):
"""
@ -48,11 +48,11 @@ class BookType(models.Model):
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
class BookReference(models.Model):
@ -100,7 +100,7 @@ class BookReference(models.Model):
ordering = ('-created_at',)
def __str__(self):
return self.title[0]['text'] if self.title else "Untitled Reference"
return self.title[0].get('title') or self.title[0].get('text', '') if self.title else "Untitled Reference"
def _get_json_field(self, field_name: str, lang: Optional[str]=None , fallback: str = "en"):
"""
@ -117,18 +117,18 @@ class BookReference(models.Model):
# 1) exact language
for item in value:
if isinstance(item, dict) and item.get("language_code") == lang:
return item.get("text", "")
return item.get("title") or item.get("text") or ""
# 2) fallback language
if fallback and fallback != lang:
for item in value:
if isinstance(item, dict) and item.get("language_code") == fallback:
return item.get("text", "")
return item.get("title") or item.get("text") or ""
# 3) first available
item = value[0]
print(item)
return item.get("text", "") if isinstance(item, dict) else None
return item.get("title") or item.get("text") if isinstance(item, dict) else None
@property
def share_link(self):
@ -157,7 +157,7 @@ class BookReference(models.Model):
if self.title and isinstance(self.title, list) and len(self.title) > 0:
first_item = self.title[0]
if isinstance(first_item, dict):
title_text = first_item.get('text', '').strip()
title_text = (first_item.get('title') or first_item.get('text') or '').strip()
if title_text:
base_slug = slugify(title_text, allow_unicode=True)
slug = base_slug
@ -240,11 +240,11 @@ class BookReferenceImage(models.Model):
for tr in self.description:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.description:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
def __str__(self):
@ -300,7 +300,7 @@ class BookAuthor(models.Model):
ordering = ['name']
def __str__(self):
return self.name[0]['text'] if self.name else "Unknown Author"
return self.name[0].get('title') or self.name[0].get('text', '') if self.name else "Unknown Author"
def get_name(self,lang):
"""
@ -312,11 +312,11 @@ class BookAuthor(models.Model):
for tr in self.name:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.name:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
@ -343,8 +343,8 @@ class BookAttribute(models.Model):
ordering = ['title']
def __str__(self):
title = self.title[0]['text'] if self.title else "No Title"
value = self.value[0]['text'] if self.value else "No Value"
title = self.title[0].get('title') or self.title[0].get('text', '') if self.title else "No Title"
value = self.value[0].get('title') or self.value[0].get('text', '') if self.value else "No Value"
return f"{title}: {value}"
def get_title(self,lang):
@ -357,11 +357,11 @@ class BookAttribute(models.Model):
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
def get_value(self,lang):
@ -374,9 +374,9 @@ class BookAttribute(models.Model):
for tr in self.value:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.value:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None

60
apps/hadis/models/transmitter.py

@ -30,7 +30,7 @@ class NarratorLayer(models.Model):
ordering = ['number']
def __str__(self):
name = self.name[0]['text'] if self.name else f"Layer {self.number}"
name = self.name[0].get('title') or self.name[0].get('text', '') if self.name else f"Layer {self.number}"
return f"{_('Layer')} {self.number} - {name}"
def get_description(self,lang):
@ -43,11 +43,11 @@ class NarratorLayer(models.Model):
for tr in self.description:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.description:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
def get_name(self,lang):
@ -60,11 +60,11 @@ class NarratorLayer(models.Model):
for tr in self.name:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.name:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
def save(self, *args, **kwargs):
@ -74,7 +74,7 @@ class NarratorLayer(models.Model):
if self.name and isinstance(self.name, list) and len(self.name) > 0:
first_item = self.name[0]
if isinstance(first_item, dict):
text = first_item.get('text', '').strip()
text = (first_item.get('title') or first_item.get('text') or '').strip()
if text:
slug = slugify(text)
# Ensure uniqueness
@ -135,7 +135,7 @@ class TransmitterReliability(ColorPaletteMixin, models.Model):
if self.title and isinstance(self.title, list) and len(self.title) > 0:
first_item = self.title[0]
if isinstance(first_item, dict):
text = first_item.get('text', '').strip()
text = (first_item.get('title') or first_item.get('text') or '').strip()
if text:
slug = slugify(text)
# Ensure uniqueness
@ -185,7 +185,7 @@ class TransmitterReliability(ColorPaletteMixin, models.Model):
super().save(*args, **kwargs)
def __str__(self):
return self.title[0]['text'] if self.title else str(self.id)
return self.title[0].get('title') or self.title[0].get('text', '') if self.title else str(self.id)
def get_title(self,lang):
"""
@ -197,11 +197,11 @@ class TransmitterReliability(ColorPaletteMixin, models.Model):
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
class Meta:
@ -314,7 +314,7 @@ class Transmitters(models.Model):
if self.full_name and isinstance(self.full_name, list) and len(self.full_name) > 0:
first_item = self.full_name[0]
if isinstance(first_item, dict):
name_text = first_item.get('text', '').strip()
name_text = (first_item.get('title') or first_item.get('text') or '').strip()
if name_text:
base_slug = slugify(name_text, allow_unicode=True)
slug = base_slug
@ -380,18 +380,18 @@ class Transmitters(models.Model):
# 1) exact language
for item in value:
if isinstance(item, dict) and item.get("language_code") == lang:
return item.get("text", "")
return item.get("title") or item.get("text") or ""
# 2) fallback language
if fallback and fallback != lang:
for item in value:
if isinstance(item, dict) and item.get("language_code") == fallback:
return item.get("text", "")
return item.get("title") or item.get("text") or ""
# 3) first available
item = value[0]
print(item)
return item.get("text", "") if isinstance(item, dict) else None
return item.get("title") or item.get("text") if isinstance(item, dict) else None
def get_full_name(self, lang):
return self._get_json_field("full_name" , lang)
@ -417,7 +417,7 @@ class Transmitters(models.Model):
def __str__(self):
if self.full_name and len(self.full_name) > 0:
return self.full_name[0].get('text', str(self.id))
return self.full_name[0].get('title') or self.full_name[0].get('text', str(self.id))
return str(self.id)
@ -498,7 +498,7 @@ class OpinionStatus(ColorPaletteMixin, models.Model):
if self.title and isinstance(self.title, list) and len(self.title) > 0:
first_item = self.title[0]
if isinstance(first_item, dict):
text = first_item.get('text', '').strip()
text = (first_item.get('title') or first_item.get('text') or '').strip()
if text:
slug = slugify(text)
# Ensure uniqueness
@ -548,7 +548,7 @@ class OpinionStatus(ColorPaletteMixin, models.Model):
super().save(*args, **kwargs)
def __str__(self):
return self.title[0]['text'] if self.title else str(self.id)
return self.title[0].get('title') or self.title[0].get('text', '') if self.title else str(self.id)
def get_title(self,lang):
"""
@ -560,11 +560,11 @@ class OpinionStatus(ColorPaletteMixin, models.Model):
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
class Meta:
@ -611,7 +611,7 @@ class TransmitterOpinion(models.Model):
ordering = ('-created_at',)
def __str__(self):
scholar = self.scholar_name[0]['text'] if self.scholar_name else "Unknown Scholar"
scholar = self.scholar_name[0].get('title') or self.scholar_name[0].get('text', '') if self.scholar_name else "Unknown Scholar"
return f"{scholar}'s opinion on {self.transmitter} ({self.status})"
def get_scholar_name(self,lang):
@ -624,11 +624,11 @@ class TransmitterOpinion(models.Model):
for tr in self.scholar_name:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.scholar_name:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
def get_opinion_tex(self,lang):
@ -641,11 +641,11 @@ class TransmitterOpinion(models.Model):
for tr in self.opinion_text:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.opinion_text:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
class TransmitterOriginalText(models.Model):
@ -671,7 +671,7 @@ class TransmitterOriginalText(models.Model):
verbose_name_plural = _('Transmitter Original Text')
def __str__(self):
title = self.title[0]['text'] if self.title else "Untitled"
title = self.title[0].get('title') or self.title[0].get('text', '') if self.title else "Untitled"
return f"{title} by {self.transmitter}"
def save(self, *args, **kwargs):
@ -686,7 +686,7 @@ class TransmitterOriginalText(models.Model):
if isinstance(self.title, list) and self.title:
first_item = self.title[0]
if isinstance(first_item, dict):
title_text = first_item.get("text")
title_text = first_item.get("title") or first_item.get("text")
# Generate smart slug
if title_text:
@ -734,11 +734,11 @@ class TransmitterOriginalText(models.Model):
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
def get_opinion_tex(self,lang):
@ -752,11 +752,11 @@ class TransmitterOriginalText(models.Model):
for tr in self.opinion_text:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
for tr in self.opinion_text:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return tr.get('title') or tr.get('text') or ''
return None
from .reference import BookReference
class OriginalTextReference(models.Model):

16
apps/hadis/serializers/category.py

@ -10,7 +10,7 @@ def get_localized_text(json_list, request=None, fallback_lang="en", language_cod
"""
Extract localized text from a JSON list based on language.
Expects: [{"language_code": "en", "text": "..."}, ...]
Expects: [{"language_code": "en", "title": "..."}, ...]
Returns: Single text string or None
"""
if not json_list or not isinstance(json_list, list):
@ -25,16 +25,16 @@ def get_localized_text(json_list, request=None, fallback_lang="en", language_cod
# 1) Exact match
for item in json_list:
if isinstance(item, dict) and item.get("language_code") == language_code:
return item.get("text")
return item.get("title") or item.get("text")
# 2) Fallback to English
for item in json_list:
if isinstance(item, dict) and item.get("language_code") == "en":
return item.get("text")
return item.get("title") or item.get("text")
# 3) First available
if json_list and isinstance(json_list[0], dict):
return json_list[0].get("text")
return json_list[0].get("title") or json_list[0].get("text")
return None
@ -47,7 +47,7 @@ class LocalizedField(serializers.Field):
"""
def to_representation(self, value):
# Expecting value to be a list of {"language_code": "...", "text": "..."}
# Expecting value to be a list of {"language_code": "...", "title": "..."}
if not value or not isinstance(value, list):
return None
@ -60,16 +60,16 @@ class LocalizedField(serializers.Field):
# 1) Exact match with request language
for item in value:
if item.get("language_code") == language_code:
return item.get("text")
return item.get("title") or item.get("text")
# 2) Fallback to English
for item in value:
if item.get("language_code") == "en":
return item.get("text")
return item.get("title") or item.get("text")
# 3) Fallback to first item
first = value[0]
return first.get("text") if isinstance(first, dict) else None
return first.get("title") or first.get("text") if isinstance(first, dict) else None
class SimpleCategory(serializers.ModelSerializer):
title = LocalizedField()

6
apps/hadis/views/category.py

@ -429,16 +429,16 @@ class HadisCategoryXMindView(APIView):
# 1. Try specific language
for item in json_field:
if item.get('language_code') == lang:
return item.get('text', '')
return item.get('title') or item.get('text', '')
# 2. Fallback to English
for item in json_field:
if item.get('language_code') == 'en':
return item.get('text', '')
return item.get('title') or item.get('text', '')
# 3. Fallback to first available
if len(json_field) > 0:
return json_field[0].get('text', '')
return json_field[0].get('title') or json_field[0].get('text', '')
return "Unknown"

Loading…
Cancel
Save