diff --git a/apps/hadis/admin/category.py b/apps/hadis/admin/category.py index b628240..73d0511 100644 --- a/apps/hadis/admin/category.py +++ b/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" diff --git a/apps/hadis/admin/hadis.py b/apps/hadis/admin/hadis.py index 1d531da..a726c98 100644 --- a/apps/hadis/admin/hadis.py +++ b/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 '-' diff --git a/apps/hadis/admin/reference.py b/apps/hadis/admin/reference.py index 41d5940..f05dbd1 100644 --- a/apps/hadis/admin/reference.py +++ b/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 '-' diff --git a/apps/hadis/admin/transmitter.py b/apps/hadis/admin/transmitter.py index c2b90e4..3b331b5 100644 --- a/apps/hadis/admin/transmitter.py +++ b/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 '-' diff --git a/apps/hadis/management/commands/migrate_json_keys.py b/apps/hadis/management/commands/migrate_json_keys.py new file mode 100644 index 0000000..cd45e2d --- /dev/null +++ b/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!")) diff --git a/apps/hadis/models/category.py b/apps/hadis/models/category.py index 9dcf51c..b676aec 100644 --- a/apps/hadis/models/category.py +++ b/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 diff --git a/apps/hadis/models/hadis.py b/apps/hadis/models/hadis.py index 0d694d5..9637af5 100644 --- a/apps/hadis/models/hadis.py +++ b/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 diff --git a/apps/hadis/models/reference.py b/apps/hadis/models/reference.py index 2d9dd97..bf561d2 100644 --- a/apps/hadis/models/reference.py +++ b/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 diff --git a/apps/hadis/models/transmitter.py b/apps/hadis/models/transmitter.py index f0fd7a1..3ad0bef 100644 --- a/apps/hadis/models/transmitter.py +++ b/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): diff --git a/apps/hadis/serializers/category.py b/apps/hadis/serializers/category.py index 38cdb13..6b128a1 100644 --- a/apps/hadis/serializers/category.py +++ b/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() diff --git a/apps/hadis/views/category.py b/apps/hadis/views/category.py index b6b4015..68eab28 100644 --- a/apps/hadis/views/category.py +++ b/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"