Browse Source

refactor models for translations

master
Mohsen Taba 5 months ago
parent
commit
4e33162943
  1. 1565
      apps/hadis/fixtures/categories_backup.json
  2. 2075
      apps/hadis/fixtures/hadises1_backup.json
  3. 2415
      apps/hadis/fixtures/hadises1_reformatted.json
  4. 2605
      apps/hadis/fixtures/hadises2_backup.json
  5. 4252
      apps/hadis/fixtures/hadises2_reformatted.json
  6. 1630
      apps/hadis/fixtures/new_categories.json
  7. 0
      apps/hadis/fixtures/references_backup.json
  8. 115
      apps/hadis/fixtures/reformat_data.py
  9. 950
      apps/hadis/fixtures/transmitters_backup.json
  10. 1580
      apps/hadis/fixtures/transmitters_reformatted.json
  11. 54
      apps/hadis/management/commands/dump_with_encoding.py
  12. 32
      apps/hadis/migrations/0050_convert_title_to_json.py
  13. 40
      apps/hadis/migrations/0051_convert_title_to_json_fixed.py
  14. 17
      apps/hadis/migrations/0052_alter_hadiscategory_title.py
  15. 27
      apps/hadis/migrations/0053_alter_hadiscategory_description_and_more.py
  16. 76
      apps/hadis/migrations/0054_remove_hadiscorrection_description_and_more.py
  17. 52
      apps/hadis/migrations/0055_alter_bookattribute_title_alter_bookattribute_value_and_more.py
  18. 82
      apps/hadis/migrations/0056_alter_narratorlayer_description_and_more.py
  19. 17
      apps/hadis/migrations/0057_hadiscorrection_description.py
  20. 8
      apps/hadis/models/category.py
  21. 89
      apps/hadis/models/hadis.py
  22. 16
      apps/hadis/models/reference.py
  23. 35
      apps/hadis/models/transmitter.py
  24. 1
      apps/hadis/serializers/category.py
  25. 9
      apps/hadis/serializers/hadis.py

1565
apps/hadis/fixtures/categories_backup.json
File diff suppressed because it is too large
View File

2075
apps/hadis/fixtures/hadises1_backup.json
File diff suppressed because it is too large
View File

2415
apps/hadis/fixtures/hadises1_reformatted.json
File diff suppressed because it is too large
View File

2605
apps/hadis/fixtures/hadises2_backup.json
File diff suppressed because it is too large
View File

4252
apps/hadis/fixtures/hadises2_reformatted.json
File diff suppressed because it is too large
View File

1630
apps/hadis/fixtures/new_categories.json
File diff suppressed because it is too large
View File

0
apps/hadis/fixtures/references_backup.json

115
apps/hadis/fixtures/reformat_data.py

@ -0,0 +1,115 @@
import json
import re
import sys
def detect_language(text):
"""
Detect language code based on text content.
- Cyrillic characters -> 'ru'
- Arabic/Persian characters -> 'fa'
- Default -> 'en'
"""
if not text or not isinstance(text, str):
return 'en'
# Check for Cyrillic (Russian)
if re.search(r'[а-яА-Я]', text):
return 'ru'
# Check for Arabic/Persian script
if re.search(r'[\u0600-\u06FF]', text):
return 'fa'
# Default to English
return 'en'
def reformat_data(input_file, output_file):
print(f"📖 Reading {input_file}...")
try:
with open(input_file, 'r', encoding='utf-8') as f:
data = json.load(f)
except FileNotFoundError:
print(f"❌ Error: File '{input_file}' not found.")
return
except json.JSONDecodeError as e:
print(f"❌ Error: Failed to decode JSON. {e}")
return
processed_count = 0
# Configuration based on your request
TARGETS = {
'hadis.narratorlayer': [
'name',
'description'
],
'hadis.transmitters': [
'full_name',
'kunya',
'known_as',
'nickname',
'origin',
'lived_in',
'died_in',
'description'
],
'hadis.transmitteropinion': [
'scholar_name',
'opinion_text'
],
'hadis.transmitteroriginaltext': [
'title',
'text'
],
}
for record in data:
model = record.get('model')
if model in TARGETS:
fields = record.get('fields', {})
target_fields = TARGETS[model]
for field in target_fields:
if field in fields:
original_value = fields[field]
# Case 1: Value is None/Null -> Empty List
if original_value is None:
fields[field] = []
continue
# Case 2: Value is String -> Convert to JSON Format
if isinstance(original_value, str):
# Detect language
lang_code = detect_language(original_value)
# Reformat
fields[field] = [
{
"text": original_value,
"language_code": lang_code
}
]
# Case 3: Already a list -> Skip
elif isinstance(original_value, list):
continue
processed_count += 1
print(f"✅ Processed {processed_count} records.")
try:
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"💾 Saved reformatted data to: {output_file}")
except Exception as e:
print(f"❌ Error writing output file: {e}")
if __name__ == "__main__":
# Input/Output filenames
INPUT_FILE = "transmitters_backup.json"
OUTPUT_FILE = "transmitters_reformatted.json"
reformat_data(INPUT_FILE, OUTPUT_FILE)

950
apps/hadis/fixtures/transmitters_backup.json

@ -0,0 +1,950 @@
[
{
"model": "hadis.narratorlayer",
"pk": 6,
"fields": {
"name": "Sahaba (Companions)",
"number": 1,
"description": "The companions of Prophet Muhammad (PBUH) who heard directly from him.",
"slug": "sahaba-companions",
"created_at": "2025-12-16T15:52:28.561",
"updated_at": "2025-12-16T15:52:28.561"
}
},
{
"model": "hadis.narratorlayer",
"pk": 7,
"fields": {
"name": "Tabi'un (Successors)",
"number": 2,
"description": "Narrators who lived after the Prophet's era and heard from the companions.",
"slug": "tabiun-successors",
"created_at": "2025-12-16T15:52:28.959",
"updated_at": "2025-12-16T15:52:28.959"
}
},
{
"model": "hadis.narratorlayer",
"pk": 8,
"fields": {
"name": "Taba' Tabi'in (Followers of Successors)",
"number": 3,
"description": "Narrators who heard from the Successors.",
"slug": "taba-tabiin-followers-of-successors",
"created_at": "2025-12-16T15:52:29.359",
"updated_at": "2025-12-16T15:52:29.359"
}
},
{
"model": "hadis.narratorlayer",
"pk": 9,
"fields": {
"name": "Later Generations",
"number": 4,
"description": "Narrators from later Islamic centuries, known for their scholarship.",
"slug": "later-generations",
"created_at": "2025-12-16T15:52:29.759",
"updated_at": "2025-12-16T15:52:29.759"
}
},
{
"model": "hadis.narratorlayer",
"pk": 10,
"fields": {
"name": "Modern Era Scholars",
"number": 5,
"description": "Contemporary scholars who have specialized knowledge of hadith narration.",
"slug": "modern-era-scholars",
"created_at": "2025-12-16T15:52:30.157",
"updated_at": "2025-12-16T15:52:30.157"
}
},
{
"model": "hadis.transmitters",
"pk": 71,
"fields": {
"full_name": "Abu Hurayrah",
"kunya": "Abu Hurayrah",
"known_as": "Abd al-Rahman ibn Sakhr",
"nickname": "Father of the Kitten",
"slug": "abu-hurayrah",
"origin": "Yamama, Arabia",
"lived_in": "Medina, Syria",
"died_in": "Medina",
"birth_year_hijri": 7,
"death_year_hijri": 58,
"age_at_death": 78,
"generation": 1,
"reliability": "very_reliable",
"madhhab": "sunni",
"in_sahih_muslim": true,
"in_sahih_bukhari": true,
"description": "One of the most prolific hadith narrators, reported 5,374 ahadith.",
"thumbnail": null,
"created_at": "2025-12-16T15:52:30.856",
"updated_at": "2025-12-17T13:33:19.654"
}
},
{
"model": "hadis.transmitters",
"pk": 72,
"fields": {
"full_name": "Aisha bint Abu Bakr",
"kunya": "Umm al-Mu'minin",
"known_as": "Mother of the Believers",
"nickname": "Al-Siddiqa",
"slug": "aisha-bint-abu-bakr",
"origin": "Medina",
"lived_in": "Medina",
"died_in": "Medina",
"birth_year_hijri": null,
"death_year_hijri": 58,
"age_at_death": 66,
"generation": 1,
"reliability": "very_reliable",
"madhhab": "sunni",
"in_sahih_muslim": true,
"in_sahih_bukhari": true,
"description": "Wife of the Prophet Muhammad (PBUH), a major source of hadith about daily life.",
"thumbnail": null,
"created_at": "2025-12-16T15:52:31.258",
"updated_at": "2025-12-17T13:33:19.843"
}
},
{
"model": "hadis.transmitters",
"pk": 73,
"fields": {
"full_name": "Jabir ibn Abdullah al-Ansari",
"kunya": "Abu Abdullah",
"known_as": "Jabir",
"nickname": "Al-Ansari",
"slug": "jabir-ibn-abdullah-al-ansari",
"origin": "Medina",
"lived_in": "Medina",
"died_in": "Medina",
"birth_year_hijri": 10,
"death_year_hijri": 74,
"age_at_death": 94,
"generation": 1,
"reliability": "very_reliable",
"madhhab": "sunni",
"in_sahih_muslim": true,
"in_sahih_bukhari": true,
"description": "One of the long-lived companions, reported numerous ahadith on various topics.",
"thumbnail": null,
"created_at": "2025-12-16T15:52:31.987",
"updated_at": "2025-12-17T13:33:20.599"
}
},
{
"model": "hadis.transmitters",
"pk": 74,
"fields": {
"full_name": "Imam Malik ibn Anas",
"kunya": "Abu Abdullah",
"known_as": "Malik",
"nickname": "Imam of Imams",
"slug": "imam-malik-ibn-anas",
"origin": "Medina",
"lived_in": "Medina",
"died_in": "Medina",
"birth_year_hijri": 93,
"death_year_hijri": 179,
"age_at_death": 86,
"generation": 3,
"reliability": "very_reliable",
"madhhab": "maliki",
"in_sahih_muslim": true,
"in_sahih_bukhari": true,
"description": "Founder of the Maliki school of Islamic jurisprudence, compiler of Al-Muwatta.",
"thumbnail": null,
"created_at": "2025-12-16T15:52:32.383",
"updated_at": "2025-12-17T13:33:20.412"
}
},
{
"model": "hadis.transmitters",
"pk": 75,
"fields": {
"full_name": "Al-Qasim ibn Muhammad",
"kunya": "Abu Muhammad",
"known_as": "Al-Qasim",
"nickname": "Son of the Rightly Guided",
"slug": "al-qasim-ibn-muhammad",
"origin": "Medina",
"lived_in": "Medina",
"died_in": "Medina",
"birth_year_hijri": 38,
"death_year_hijri": 106,
"age_at_death": 68,
"generation": 2,
"reliability": "reliable",
"madhhab": "sunni",
"in_sahih_muslim": true,
"in_sahih_bukhari": true,
"description": "Son of Amir al-Mu'minin, known for his knowledge of Islamic jurisprudence.",
"thumbnail": null,
"created_at": "2025-12-16T15:52:32.785",
"updated_at": "2025-12-17T13:33:20.031"
}
},
{
"model": "hadis.transmitters",
"pk": 76,
"fields": {
"full_name": "Urwa ibn al-Zubayr",
"kunya": "Abu Abdullah",
"known_as": "Urwa",
"nickname": "The Jurist",
"slug": "urwa-ibn-al-zubayr",
"origin": "Medina",
"lived_in": "Medina, Mecca",
"died_in": "Medina",
"birth_year_hijri": 23,
"death_year_hijri": 94,
"age_at_death": 71,
"generation": 2,
"reliability": "very_reliable",
"madhhab": "sunni",
"in_sahih_muslim": true,
"in_sahih_bukhari": true,
"description": "Prominent Tabi'un scholar and transmitter of hadith from Aisha.",
"thumbnail": null,
"created_at": "2025-12-16T15:52:33.184",
"updated_at": "2025-12-17T13:33:21.165"
}
},
{
"model": "hadis.transmitters",
"pk": 77,
"fields": {
"full_name": "Abdullah ibn Abbas",
"kunya": "Abu Abbas",
"known_as": "Ibn Abbas",
"nickname": "Hibr al-Ummah (The Learned Scholar of the Nation)",
"slug": "abdullah-ibn-abbas",
"origin": "Medina",
"lived_in": "Medina, Mecca, Basra",
"died_in": "Taif",
"birth_year_hijri": 3,
"death_year_hijri": 68,
"age_at_death": 71,
"generation": 1,
"reliability": "very_reliable",
"madhhab": "sunni",
"in_sahih_muslim": true,
"in_sahih_bukhari": true,
"description": "Cousin of the Prophet (PBUH), famous for Quranic exegesis and hadith knowledge.",
"thumbnail": null,
"created_at": "2025-12-16T15:52:33.582",
"updated_at": "2025-12-17T13:33:19.464"
}
},
{
"model": "hadis.transmitters",
"pk": 78,
"fields": {
"full_name": "Nafi' (Mawla of Ibn Umar)",
"kunya": "Abu Abdullah",
"known_as": "Nafi'",
"nickname": "The Freed Slave",
"slug": "nafi-mawla-of-ibn-umar",
"origin": "Ethiopia",
"lived_in": "Medina",
"died_in": "Medina",
"birth_year_hijri": 25,
"death_year_hijri": 117,
"age_at_death": 92,
"generation": 2,
"reliability": "very_reliable",
"madhhab": "sunni",
"in_sahih_muslim": true,
"in_sahih_bukhari": true,
"description": "Freed slave of Abdullah ibn Umar, transmitted numerous hadith from him.",
"thumbnail": null,
"created_at": "2025-12-16T15:52:33.979",
"updated_at": "2025-12-17T13:33:20.788"
}
},
{
"model": "hadis.transmitters",
"pk": 79,
"fields": {
"full_name": "Imam Ahmad ibn Hanbal",
"kunya": "Abu Abdullah",
"known_as": "Ahmad",
"nickname": "Shaykh al-Islam",
"slug": "imam-ahmad-ibn-hanbal",
"origin": "Khorasan",
"lived_in": "Baghdad",
"died_in": "Baghdad",
"birth_year_hijri": 164,
"death_year_hijri": 241,
"age_at_death": 77,
"generation": 4,
"reliability": "very_reliable",
"madhhab": "hanbali",
"in_sahih_muslim": false,
"in_sahih_bukhari": false,
"description": "Founder of the Hanbali school, compiler of Musnad Ahmad with 40,000+ hadith.",
"thumbnail": null,
"created_at": "2025-12-16T15:52:34.376",
"updated_at": "2025-12-17T13:33:20.222"
}
},
{
"model": "hadis.transmitters",
"pk": 80,
"fields": {
"full_name": "Sufyan ibn Uyayna",
"kunya": "Abu Muhammad",
"known_as": "Sufyan",
"nickname": "Amir al-Mu'minin fil-Hadith",
"slug": "sufyan-ibn-uyayna",
"origin": "Kufa",
"lived_in": "Mecca, Kufa",
"died_in": "Mecca",
"birth_year_hijri": 107,
"death_year_hijri": 198,
"age_at_death": 91,
"generation": 3,
"reliability": "very_reliable",
"madhhab": "shafii",
"in_sahih_muslim": true,
"in_sahih_bukhari": true,
"description": "Great hadith scholar and judge, known for his exceptional memory.",
"thumbnail": null,
"created_at": "2025-12-16T15:52:34.779",
"updated_at": "2025-12-17T13:33:20.976"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6285,
"fields": {
"hadis": 1800,
"transmitter": 71,
"narrator_layer": 6,
"status": "reliable",
"order": 1,
"is_gap": false,
"created_at": "2025-12-16T15:52:42.368"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6286,
"fields": {
"hadis": 1800,
"transmitter": 74,
"narrator_layer": 8,
"status": "reliable",
"order": 2,
"is_gap": false,
"created_at": "2025-12-16T15:52:42.770"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6287,
"fields": {
"hadis": 1801,
"transmitter": 72,
"narrator_layer": 6,
"status": "reliable",
"order": 1,
"is_gap": false,
"created_at": "2025-12-16T15:52:43.168"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6288,
"fields": {
"hadis": 1801,
"transmitter": 76,
"narrator_layer": 7,
"status": "reliable",
"order": 2,
"is_gap": false,
"created_at": "2025-12-16T15:52:43.568"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6289,
"fields": {
"hadis": 1801,
"transmitter": 74,
"narrator_layer": 8,
"status": "reliable",
"order": 3,
"is_gap": false,
"created_at": "2025-12-16T15:52:43.969"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6290,
"fields": {
"hadis": 1802,
"transmitter": 73,
"narrator_layer": 6,
"status": "reliable",
"order": 1,
"is_gap": false,
"created_at": "2025-12-16T15:52:44.368"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6291,
"fields": {
"hadis": 1802,
"transmitter": 75,
"narrator_layer": 7,
"status": "reliable",
"order": 2,
"is_gap": false,
"created_at": "2025-12-16T15:52:44.769"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6292,
"fields": {
"hadis": 1802,
"transmitter": 80,
"narrator_layer": 8,
"status": "reliable",
"order": 3,
"is_gap": false,
"created_at": "2025-12-16T15:52:45.168"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6293,
"fields": {
"hadis": 1803,
"transmitter": 77,
"narrator_layer": 6,
"status": "reliable",
"order": 1,
"is_gap": false,
"created_at": "2025-12-16T15:52:45.566"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6294,
"fields": {
"hadis": 1803,
"transmitter": 78,
"narrator_layer": 7,
"status": "reliable",
"order": 2,
"is_gap": false,
"created_at": "2025-12-16T15:52:45.966"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6295,
"fields": {
"hadis": 1803,
"transmitter": 79,
"narrator_layer": 8,
"status": "reliable",
"order": 3,
"is_gap": false,
"created_at": "2025-12-16T15:52:46.366"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6296,
"fields": {
"hadis": 1804,
"transmitter": 71,
"narrator_layer": 6,
"status": "reliable",
"order": 1,
"is_gap": false,
"created_at": "2025-12-16T15:52:46.770"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6297,
"fields": {
"hadis": 1804,
"transmitter": 80,
"narrator_layer": 8,
"status": "reliable",
"order": 2,
"is_gap": false,
"created_at": "2025-12-16T15:52:47.176"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6298,
"fields": {
"hadis": 1805,
"transmitter": 72,
"narrator_layer": 6,
"status": "reliable",
"order": 1,
"is_gap": false,
"created_at": "2025-12-16T15:52:47.577"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6299,
"fields": {
"hadis": 1805,
"transmitter": 75,
"narrator_layer": 7,
"status": "reliable",
"order": 2,
"is_gap": false,
"created_at": "2025-12-16T15:52:47.977"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6300,
"fields": {
"hadis": 1806,
"transmitter": 73,
"narrator_layer": 6,
"status": "reliable",
"order": 1,
"is_gap": false,
"created_at": "2025-12-16T15:52:48.377"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6301,
"fields": {
"hadis": 1806,
"transmitter": 78,
"narrator_layer": 7,
"status": "reliable",
"order": 2,
"is_gap": false,
"created_at": "2025-12-16T15:52:48.774"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6302,
"fields": {
"hadis": 1806,
"transmitter": 74,
"narrator_layer": 8,
"status": "reliable",
"order": 3,
"is_gap": false,
"created_at": "2025-12-16T15:52:49.173"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6303,
"fields": {
"hadis": 1806,
"transmitter": 80,
"narrator_layer": 8,
"status": "reliable",
"order": 4,
"is_gap": false,
"created_at": "2025-12-16T15:52:49.575"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6304,
"fields": {
"hadis": 1807,
"transmitter": 77,
"narrator_layer": 6,
"status": "reliable",
"order": 1,
"is_gap": false,
"created_at": "2025-12-16T15:52:49.973"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6305,
"fields": {
"hadis": 1807,
"transmitter": 76,
"narrator_layer": 7,
"status": "reliable",
"order": 2,
"is_gap": false,
"created_at": "2025-12-16T15:52:50.371"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6306,
"fields": {
"hadis": 1807,
"transmitter": 79,
"narrator_layer": 8,
"status": "reliable",
"order": 3,
"is_gap": false,
"created_at": "2025-12-16T15:52:50.770"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6307,
"fields": {
"hadis": 1808,
"transmitter": 71,
"narrator_layer": 6,
"status": "reliable",
"order": 1,
"is_gap": false,
"created_at": "2025-12-16T15:52:51.167"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6308,
"fields": {
"hadis": 1808,
"transmitter": 75,
"narrator_layer": 7,
"status": "reliable",
"order": 2,
"is_gap": false,
"created_at": "2025-12-16T15:52:51.565"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6309,
"fields": {
"hadis": 1808,
"transmitter": 74,
"narrator_layer": 8,
"status": "reliable",
"order": 3,
"is_gap": false,
"created_at": "2025-12-16T15:52:51.964"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6310,
"fields": {
"hadis": 1808,
"transmitter": 80,
"narrator_layer": 8,
"status": "reliable",
"order": 4,
"is_gap": false,
"created_at": "2025-12-16T15:52:52.358"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6311,
"fields": {
"hadis": 1809,
"transmitter": 72,
"narrator_layer": 6,
"status": "reliable",
"order": 1,
"is_gap": false,
"created_at": "2025-12-16T15:52:52.758"
}
},
{
"model": "hadis.hadistransmitter",
"pk": 6312,
"fields": {
"hadis": 1809,
"transmitter": 78,
"narrator_layer": 7,
"status": "reliable",
"order": 2,
"is_gap": false,
"created_at": "2025-12-16T15:52:53.158"
}
},
{
"model": "hadis.transmitteropinion",
"pk": 15,
"fields": {
"transmitter": 71,
"scholar_name": "Imam al-Bukhari",
"opinion_text": "Abu Hurayrah is one of the most reliable narrators with a perfect memory and integrity.",
"status": "confirmed",
"created_at": "2025-12-16T15:52:35.176",
"updated_at": "2025-12-16T15:52:35.176"
}
},
{
"model": "hadis.transmitteropinion",
"pk": 16,
"fields": {
"transmitter": 71,
"scholar_name": "Imam Muslim",
"opinion_text": "His narrations are authentic and widely accepted in the Islamic jurisprudence.",
"status": "confirmed",
"created_at": "2025-12-16T15:52:35.575",
"updated_at": "2025-12-16T15:52:35.575"
}
},
{
"model": "hadis.transmitteropinion",
"pk": 17,
"fields": {
"transmitter": 72,
"scholar_name": "Imam al-Bukhari",
"opinion_text": "The Mother of the Believers is the most reliable source for hadith about the Prophet's household.",
"status": "confirmed",
"created_at": "2025-12-16T15:52:35.972",
"updated_at": "2025-12-16T15:52:35.972"
}
},
{
"model": "hadis.transmitteropinion",
"pk": 18,
"fields": {
"transmitter": 73,
"scholar_name": "Ibn Hajar al-Asqalani",
"opinion_text": "His longevity allowed him to transmit from many companions and successors.",
"status": "confirmed",
"created_at": "2025-12-16T15:52:36.371",
"updated_at": "2025-12-16T15:52:36.371"
}
},
{
"model": "hadis.transmitteropinion",
"pk": 19,
"fields": {
"transmitter": 74,
"scholar_name": "Imam ash-Shafi'i",
"opinion_text": "Malik is among the most knowledgeable of the Medinese scholars in jurisprudence.",
"status": "confirmed",
"created_at": "2025-12-16T15:52:36.773",
"updated_at": "2025-12-16T15:52:36.773"
}
},
{
"model": "hadis.transmitteropinion",
"pk": 20,
"fields": {
"transmitter": 74,
"scholar_name": "Imam Ahmad ibn Hanbal",
"opinion_text": "Malik's narrations form the basis of sound Islamic jurisprudence.",
"status": "confirmed",
"created_at": "2025-12-16T15:52:37.171",
"updated_at": "2025-12-16T15:52:37.171"
}
},
{
"model": "hadis.transmitteropinion",
"pk": 21,
"fields": {
"transmitter": 75,
"scholar_name": "Ibn Hajar al-Asqalani",
"opinion_text": "Al-Qasim is a trustworthy narrator from the Tabi'un generation with reliable traditions.",
"status": "confirmed",
"created_at": "2025-12-16T15:52:37.570",
"updated_at": "2025-12-16T15:52:37.570"
}
},
{
"model": "hadis.transmitteropinion",
"pk": 22,
"fields": {
"transmitter": 76,
"scholar_name": "Imam al-Bukhari",
"opinion_text": "Urwa is among the most knowledgeable about the traditions of the Prophet's household.",
"status": "confirmed",
"created_at": "2025-12-16T15:52:37.969",
"updated_at": "2025-12-16T15:52:37.969"
}
},
{
"model": "hadis.transmitteropinion",
"pk": 23,
"fields": {
"transmitter": 77,
"scholar_name": "Imam at-Tirmidhi",
"opinion_text": "Ibn Abbas has exceptional knowledge in Quranic interpretation and hadith narration.",
"status": "confirmed",
"created_at": "2025-12-16T15:52:38.369",
"updated_at": "2025-12-16T15:52:38.369"
}
},
{
"model": "hadis.transmitteropinion",
"pk": 24,
"fields": {
"transmitter": 78,
"scholar_name": "Imam Muslim",
"opinion_text": "Nafi' is one of the most reliable freed slaves who transmitted authentic traditions.",
"status": "confirmed",
"created_at": "2025-12-16T15:52:38.767",
"updated_at": "2025-12-16T15:52:38.767"
}
},
{
"model": "hadis.transmitteropinion",
"pk": 25,
"fields": {
"transmitter": 79,
"scholar_name": "Ibn Hajar al-Asqalani",
"opinion_text": "Ahmad ibn Hanbal's knowledge of hadith is unparalleled in his era.",
"status": "confirmed",
"created_at": "2025-12-16T15:52:39.166",
"updated_at": "2025-12-16T15:52:39.166"
}
},
{
"model": "hadis.transmitteropinion",
"pk": 26,
"fields": {
"transmitter": 80,
"scholar_name": "Imam al-Bukhari",
"opinion_text": "Sufyan is a highly reliable hadith scholar with exceptional memory.",
"status": "confirmed",
"created_at": "2025-12-16T15:52:39.563",
"updated_at": "2025-12-16T15:52:39.563"
}
},
{
"model": "hadis.transmitteroriginaltext",
"pk": 9,
"fields": {
"transmitter": 71,
"title": "His Narration on Zakat",
"text": "حدثنا أبو هريرة قال: قال رسول الله صلى الله عليه وسلم: من آمن بالله واليوم الآخر فليؤد الزكاة",
"translation": [
{
"text": "Abu Hurayrah narrated: The Messenger of Allah (PBUH) said: Whoever believes in Allah and the Last Day, let him pay the Zakat (alms).",
"language_code": "en"
},
{
"text": "أبو هريرة: من آمن بالله واليوم الآخر فليؤد الزكاة",
"language_code": "ar"
}
],
"share_link": "https://hadith.example.com/abu-hurayrah/zakat-1"
}
},
{
"model": "hadis.transmitteroriginaltext",
"pk": 10,
"fields": {
"transmitter": 72,
"title": "Her Account of the Prophet's Night Prayer",
"text": "قالت عائشة: كان النبي صلى الله عليه وسلم يقوم الليل فيصلي ثلاث عشرة ركعة",
"translation": [
{
"text": "Aisha said: The Prophet (PBUH) used to pray at night thirteen rak'ahs.",
"language_code": "en"
},
{
"text": "عائشة: كان النبي يقوم الليل بثلاث عشرة ركعة",
"language_code": "ar"
}
],
"share_link": "https://hadith.example.com/aisha/night-prayer-1"
}
},
{
"model": "hadis.transmitteroriginaltext",
"pk": 11,
"fields": {
"transmitter": 73,
"title": "The Farewell Hajj Narration",
"text": "قال جابر: خرجنا مع رسول الله صلى الله عليه وسلم في حجة الوداع",
"translation": [
{
"text": "Jabir narrated: We went out with the Messenger of Allah (PBUH) for the Farewell Hajj.",
"language_code": "en"
},
{
"text": "جابر: خرجنا مع رسول الله في حجة الوداع",
"language_code": "ar"
}
],
"share_link": "https://hadith.example.com/jabir/farewell-hajj-1"
}
},
{
"model": "hadis.transmitteroriginaltext",
"pk": 12,
"fields": {
"transmitter": 74,
"title": "Narration on Purity and Prayer",
"text": "قال مالك: الطهارة شرط من شروط الصلاة",
"translation": [
{
"text": "Malik said: Purification is a condition for the validity of prayer.",
"language_code": "en"
},
{
"text": "مالك: الطهارة من شروط صحة الصلاة",
"language_code": "ar"
}
],
"share_link": "https://hadith.example.com/malik/purity-1"
}
},
{
"model": "hadis.transmitteroriginaltext",
"pk": 13,
"fields": {
"transmitter": 77,
"title": "His Commentary on Divine Justice",
"text": "قال ابن عباس: إن الله تعالى عدل لا يظلم أحدا",
"translation": [
{
"text": "Ibn Abbas said: Truly Allah is Just and does not oppress anyone.",
"language_code": "en"
},
{
"text": "ابن عباس: الله عدل لا يظلم أحدا",
"language_code": "ar"
}
],
"share_link": "https://hadith.example.com/ibn-abbas/justice-1"
}
},
{
"model": "hadis.transmitteroriginaltext",
"pk": 14,
"fields": {
"transmitter": 80,
"title": "Teaching on Knowledge Seeking",
"text": "قال سفيان بن عيينة: طلب العلم فريضة على كل مسلم",
"translation": [
{
"text": "Sufyan ibn Uyayna said: Seeking knowledge is an obligation for every Muslim.",
"language_code": "en"
},
{
"text": "سفيان: طلب العلم فريضة على كل مسلم",
"language_code": "ar"
}
],
"share_link": "https://hadith.example.com/sufyan/knowledge-1"
}
}
]

1580
apps/hadis/fixtures/transmitters_reformatted.json
File diff suppressed because it is too large
View File

54
apps/hadis/management/commands/dump_with_encoding.py

@ -0,0 +1,54 @@
# hadis/management/commands/dump_with_encoding.py
from django.core.management.base import BaseCommand
from django.core.management import call_command
import sys
import os
class Command(BaseCommand):
help = 'Dump data with proper UTF-8 encoding'
def add_arguments(self, parser):
parser.add_argument(
'models',
nargs='+',
type=str,
help='Models to dump (e.g., hadis.HadisCategory hadis.HadisSect)'
)
parser.add_argument(
'--output',
type=str,
default='fixture.json',
help='Output file path'
)
parser.add_argument(
'--indent',
type=int,
default=2,
help='JSON indent level'
)
def handle(self, *args, **options):
models = options['models']
output_file = options['output']
indent = options['indent']
# Ensure directory exists
os.makedirs(os.path.dirname(output_file) or '.', exist_ok=True)
self.stdout.write(f'Dumping models: {", ".join(models)}...')
try:
# Force UTF-8 encoding
with open(output_file, 'w', encoding='utf-8') as f:
call_command(
'dumpdata',
*models,
indent=indent,
stdout=f
)
self.stdout.write(
self.style.SUCCESS(f'✓ Successfully dumped to {output_file}')
)
except Exception as e:
self.stdout.write(self.style.ERROR(f'✗ Error: {str(e)}'))

32
apps/hadis/migrations/0050_convert_title_to_json.py

@ -0,0 +1,32 @@
from django.db import migrations
import json
def convert_to_json(apps, schema_editor):
"""Convert CharField strings to JSON array of language objects"""
HadisCategory = apps.get_model('hadis', 'HadisCategory')
for obj in HadisCategory.objects.all():
# Convert plain string to JSON array with language objects
if obj.title and isinstance(obj.title, str):
# Wrap string in JSON format: [{"text": "string", "language_code": "en"}]
obj.title = [{"text": obj.title, "language_code": "en"}]
obj.save(update_fields=['title'])
def reverse_convert(apps, schema_editor):
"""Revert JSON back to plain text (optional)"""
HadisCategory = apps.get_model('hadis', 'HadisCategory')
for obj in HadisCategory.objects.all():
if obj.title and isinstance(obj.title, list) and len(obj.title) > 0:
# Extract first language's text
obj.title = obj.title[0].get('text', '')
obj.save(update_fields=['title'])
class Migration(migrations.Migration):
dependencies = [
('hadis', '0049_alter_transmitters_slug'), # Adjust to your last working migration
]
operations = [
migrations.RunPython(convert_to_json, reverse_convert),
]

40
apps/hadis/migrations/0051_convert_title_to_json_fixed.py

@ -0,0 +1,40 @@
from django.db import migrations
import json
def convert_to_json(apps, schema_editor):
"""Convert CharField strings to JSON array of language objects"""
HadisCategory = apps.get_model('hadis', 'HadisCategory')
for obj in HadisCategory.objects.all():
# Convert plain string to JSON array with language objects
if obj.title and isinstance(obj.title, str):
# Create Python dict, then serialize to valid JSON
title_data = [{"text": obj.title, "language_code": "en"}]
# CRITICAL: Use json.dumps() to convert to valid JSON string
obj.title = json.dumps(title_data)
obj.save(update_fields=['title'])
def reverse_convert(apps, schema_editor):
"""Revert JSON back to plain text (optional)"""
HadisCategory = apps.get_model('hadis', 'HadisCategory')
for obj in HadisCategory.objects.all():
if obj.title:
try:
# Parse JSON string back to Python object
title_data = json.loads(obj.title) if isinstance(obj.title, str) else obj.title
if isinstance(title_data, list) and len(title_data) > 0:
# Extract first language's text
obj.title = title_data[0].get('text', '')
obj.save(update_fields=['title'])
except (json.JSONDecodeError, TypeError):
pass
class Migration(migrations.Migration):
dependencies = [
('hadis', '0050_convert_title_to_json'), # Adjust to your last working migration
]
operations = [
migrations.RunPython(convert_to_json, reverse_convert),
]

17
apps/hadis/migrations/0052_alter_hadiscategory_title.py

@ -0,0 +1,17 @@
# Generated by Django 5.2.9 on 2025-12-17 15:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("hadis", "0051_convert_title_to_json_fixed"),
]
operations = [
migrations.AlterField(
model_name="hadiscategory",
name="title",
field=models.JSONField(default=list, verbose_name="Title"),
),
]

27
apps/hadis/migrations/0053_alter_hadiscategory_description_and_more.py

@ -0,0 +1,27 @@
# Generated by Django 5.2.9 on 2025-12-18 10:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("hadis", "0052_alter_hadiscategory_title"),
]
operations = [
migrations.AlterField(
model_name="hadiscategory",
name="description",
field=models.JSONField(default=list, verbose_name="Description"),
),
migrations.AlterField(
model_name="hadissect",
name="description",
field=models.JSONField(default=list, verbose_name="Description"),
),
migrations.AlterField(
model_name="hadissect",
name="title",
field=models.JSONField(default=list, verbose_name="Title"),
),
]

76
apps/hadis/migrations/0054_remove_hadiscorrection_description_and_more.py

@ -0,0 +1,76 @@
# Generated by Django 5.2.9 on 2025-12-18 10:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("hadis", "0053_alter_hadiscategory_description_and_more"),
]
operations = [
migrations.RemoveField(
model_name="hadiscorrection",
name="description",
),
migrations.AlterField(
model_name="hadis",
name="address",
field=models.JSONField(default=list, verbose_name="Address"),
),
migrations.AlterField(
model_name="hadis",
name="description",
field=models.JSONField(default=list, verbose_name="Description"),
),
migrations.AlterField(
model_name="hadis",
name="explanation",
field=models.JSONField(default=list, verbose_name="Explanation"),
),
migrations.AlterField(
model_name="hadis",
name="hadis_status_text",
field=models.JSONField(default=list, verbose_name="Status text"),
),
migrations.AlterField(
model_name="hadis",
name="title",
field=models.JSONField(default=list, verbose_name="Title"),
),
migrations.AlterField(
model_name="hadis",
name="title_narrator",
field=models.JSONField(default=list, verbose_name="Title Narrator"),
),
migrations.AlterField(
model_name="hadiscollection",
name="summary",
field=models.JSONField(default=list, verbose_name="Summary"),
),
migrations.AlterField(
model_name="hadiscollection",
name="title",
field=models.JSONField(default=list, verbose_name="Title"),
),
migrations.AlterField(
model_name="hadiscorrection",
name="title",
field=models.JSONField(default=list, verbose_name="Title"),
),
migrations.AlterField(
model_name="hadisreference",
name="description",
field=models.JSONField(default=list, verbose_name="Description"),
),
migrations.AlterField(
model_name="hadisstatus",
name="title",
field=models.JSONField(default=list, verbose_name="Title"),
),
migrations.AlterField(
model_name="hadistag",
name="title",
field=models.JSONField(default=list, verbose_name="Title"),
),
]

52
apps/hadis/migrations/0055_alter_bookattribute_title_alter_bookattribute_value_and_more.py

@ -0,0 +1,52 @@
# Generated by Django 5.2.9 on 2025-12-18 10:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("hadis", "0054_remove_hadiscorrection_description_and_more"),
]
operations = [
migrations.AlterField(
model_name="bookattribute",
name="title",
field=models.JSONField(default=list, verbose_name="Title"),
),
migrations.AlterField(
model_name="bookattribute",
name="value",
field=models.JSONField(default=list, verbose_name="Value"),
),
migrations.AlterField(
model_name="bookauthor",
name="name",
field=models.JSONField(default=list, verbose_name="Name"),
),
migrations.AlterField(
model_name="bookreference",
name="description",
field=models.JSONField(default=list, verbose_name="Description"),
),
migrations.AlterField(
model_name="bookreference",
name="language",
field=models.JSONField(default=list, verbose_name="Language"),
),
migrations.AlterField(
model_name="bookreference",
name="publisher",
field=models.JSONField(default=list, verbose_name="Publisher"),
),
migrations.AlterField(
model_name="bookreference",
name="title",
field=models.JSONField(default=list, verbose_name="Title"),
),
migrations.AlterField(
model_name="bookreferenceimage",
name="description",
field=models.JSONField(default=list, verbose_name="Description"),
),
]

82
apps/hadis/migrations/0056_alter_narratorlayer_description_and_more.py

@ -0,0 +1,82 @@
# Generated by Django 5.2.9 on 2025-12-18 10:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("hadis", "0055_alter_bookattribute_title_alter_bookattribute_value_and_more"),
]
operations = [
migrations.AlterField(
model_name="narratorlayer",
name="description",
field=models.JSONField(default=list, verbose_name="Description"),
),
migrations.AlterField(
model_name="narratorlayer",
name="name",
field=models.JSONField(default=list, verbose_name="Name"),
),
migrations.AlterField(
model_name="transmitteropinion",
name="opinion_text",
field=models.JSONField(default=list, verbose_name="Opinion Text"),
),
migrations.AlterField(
model_name="transmitteropinion",
name="scholar_name",
field=models.JSONField(default=list, verbose_name="Scholar Name"),
),
migrations.AlterField(
model_name="transmitteroriginaltext",
name="text",
field=models.JSONField(default=list, verbose_name="Text"),
),
migrations.AlterField(
model_name="transmitteroriginaltext",
name="title",
field=models.JSONField(default=list, verbose_name="Title"),
),
migrations.AlterField(
model_name="transmitters",
name="description",
field=models.JSONField(default=list, verbose_name="Description"),
),
migrations.AlterField(
model_name="transmitters",
name="died_in",
field=models.JSONField(default=list, verbose_name="Died in"),
),
migrations.AlterField(
model_name="transmitters",
name="full_name",
field=models.JSONField(default=list, verbose_name="Full Name"),
),
migrations.AlterField(
model_name="transmitters",
name="known_as",
field=models.JSONField(default=list, verbose_name="Known as"),
),
migrations.AlterField(
model_name="transmitters",
name="kunya",
field=models.JSONField(default=list, verbose_name="Kunya"),
),
migrations.AlterField(
model_name="transmitters",
name="lived_in",
field=models.JSONField(default=list, verbose_name="Lived in"),
),
migrations.AlterField(
model_name="transmitters",
name="nickname",
field=models.JSONField(default=list, verbose_name="Nick Name"),
),
migrations.AlterField(
model_name="transmitters",
name="origin",
field=models.JSONField(default=list, verbose_name="Origin"),
),
]

17
apps/hadis/migrations/0057_hadiscorrection_description.py

@ -0,0 +1,17 @@
# Generated by Django 5.2.9 on 2025-12-18 12:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("hadis", "0056_alter_narratorlayer_description_and_more"),
]
operations = [
migrations.AddField(
model_name="hadiscorrection",
name="description",
field=models.JSONField(default=list, verbose_name="Description"),
),
]

8
apps/hadis/models/category.py

@ -11,8 +11,8 @@ class HadisSect(models.Model):
SUNNI = 'sunni', _('Sunni')
sect_type = models.CharField(max_length=10, choices=SectType.choices, unique=True, verbose_name=_('Sect Name'))
title = models.CharField(max_length=256, verbose_name=_('Name'))
description = models.TextField(verbose_name=_('Description'), null=True, blank=True)
title = models.JSONField(default = list , verbose_name=_('Title'))
description = models.JSONField(default = list , verbose_name=_('Description'))
is_active = models.BooleanField(default=True, verbose_name=_('Is Active'))
order = models.IntegerField(default=0, verbose_name=_('order'))
@ -37,8 +37,8 @@ class HadisCategory(MPTTModel):
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
sect = models.ForeignKey(HadisSect, on_delete=models.PROTECT, verbose_name=_('Sect'), null=False, blank=False)
source_type = models.CharField(max_length=10, choices=SourceType.choices, verbose_name=_('Source Type'))
title = models.CharField(max_length=256, verbose_name=_('Title'))
description = models.TextField(verbose_name=_('Description'), null=True, blank=True)
title = models.JSONField(default = list , verbose_name=_('Title'))
description = models.JSONField(default = list , verbose_name=_('Description'))
order = models.IntegerField(default=0, verbose_name=_('order'))
xmind_file = models.FileField(upload_to='hadis/xmind_files/', verbose_name=_('xmind file'), null=True, blank=True)
slug = models.SlugField(max_length=255, null=True, blank=True)

89
apps/hadis/models/hadis.py

@ -8,9 +8,9 @@ from .reference import BookReference
class HadisCollection(models.Model):
title = models.CharField(max_length=255, verbose_name=_('title'))
title = models.JSONField(default = list , verbose_name=_('Title'))
slug = models.SlugField(max_length=255, unique=True, verbose_name=_('slug'), blank=True)
summary = models.TextField(verbose_name=_('summary'), null=True, blank=True)
summary = models.JSONField(default = list , verbose_name=_('Summary'))
status = models.BooleanField(default=True, verbose_name=_('status'))
order = models.IntegerField(default=0, verbose_name=_('order'))
thumbnail = FilerImageField(
@ -61,7 +61,7 @@ class HadisInCollection(models.Model):
class HadisTag(models.Model):
title = models.CharField(max_length=355, verbose_name=_('title'))
title = models.JSONField(default = list , verbose_name=_('Title'))
status = models.BooleanField(default=True, verbose_name=_('status'))
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'))
updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at'))
@ -80,7 +80,7 @@ class HadisStatus(models.Model):
PURPLE = 'purple', _('Purple')
GRAY = 'gray', _('Gray')
title = models.CharField(max_length=119, verbose_name=_('title'))
title = models.JSONField(default = list , verbose_name=_('Title'))
color = models.CharField(max_length=20, choices=ColorChoices.choices, verbose_name=_('color'))
order = models.IntegerField(default=0, verbose_name=_('order'))
@ -99,22 +99,22 @@ class HadisStatus(models.Model):
class Hadis(models.Model):
category = models.ForeignKey("hadis.HadisCategory", on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('category'))
number = models.PositiveIntegerField(verbose_name=_('number'), default=1)
title_narrator = models.CharField(max_length=255, verbose_name=_('title narrator'), null=True, blank=True)
title = models.CharField(max_length=255, verbose_name=_('title'), null=True, blank=True)
description = models.TextField(verbose_name=_('description'), blank=True, null=True)
title_narrator = models.JSONField(default = list , verbose_name=_('Title Narrator'))
title = models.JSONField(default = list , verbose_name=_('Title'))
description = models.JSONField(default = list , verbose_name=_('Description'))
text = models.TextField(verbose_name=_('text'))
translation = models.JSONField(verbose_name=_('translation'), default=list)
status = models.BooleanField(default=True, verbose_name=_('visibility'))
hadis_status = models.ForeignKey(HadisStatus, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('hadis status'))
hadis_status_text = models.CharField(max_length=255, verbose_name=_('hadis status text'), null=True, blank=True)
address = models.TextField(verbose_name=_('address'), null=True, blank=True)
hadis_status_text = models.JSONField(default = list , verbose_name=_('Status text'))
address = models.JSONField(default = list , verbose_name=_('Address'))
links = models.JSONField(verbose_name=_('links'), null=True, blank=True, default=dict)
tags = models.ManyToManyField("HadisTag", related_name="hadis_overview", verbose_name=_('tags'), blank=True)
share_link = models.CharField(max_length=255, verbose_name=_('share link'), null=True, blank=True)
explanation = models.TextField(verbose_name=_('explanation'), null=True, blank=True)
explanation = models.JSONField(default = list , verbose_name=_('Explanation'))
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'))
updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at'))
@ -122,21 +122,64 @@ class Hadis(models.Model):
def __str__(self):
return f"{self.number} - {self.title}" if self.title else f"Hadis {self.number}"
def get_translation(self, lang):
def _get_json_field(self, field_name: str, lang: str | None = None, fallback: str = "en"):
"""
Get translation for a specific language
Generic getter for JSONField in our [{text, language_code}] format.
Usage: self._get_json_field('title', 'fa')
"""
if not self.translation or not isinstance(self.translation, list):
if lang is None:
lang = fallback
value = getattr(self, field_name, None)
if not value or not isinstance(value, list):
return None
for tr in self.translation:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('title', '')
# 1) exact language
for item in value:
if isinstance(item, dict) and item.get("language_code") == lang:
return item.get("text", "")
for tr in self.translation:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('title', '')
return None
# 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", "")
# 3) first available
item = value[0]
print(item)
return item.get("text", "") if isinstance(item, dict) else None
def get_translation(self, lang):
return self._get_json_field("translation" , lang)
def get_title(self,lang):
return self._get_json_field("title" , lang)
def get_description(self, lang):
return self._get_json_field("description" , lang)
def get_hadis_status_text(self, lang):
return self._get_json_field("hadis_status_text" , lang)
def get_address(self, lang):
return self._get_json_field("address" , lang)
def get_explanation(self, lang):
return self._get_json_field("explanation" , lang)
# """
# Get translation for a specific language
# """
# 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('title', '')
# for tr in self.translation:
# if isinstance(tr, dict) and tr.get('language_code') == 'en':
# return tr.get('title', '')
# return None
def save(self, *args, **kwargs):
# ساخت share_link قبل از ذخیره
@ -169,7 +212,7 @@ class HadisReference(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'))
description = models.TextField(verbose_name=_('description'), null=True, blank=True)
description = models.JSONField(default = list , verbose_name=_('Description'))
class Meta:
verbose_name = _('Hadis Reference')
@ -207,8 +250,8 @@ class ReferenceImage(models.Model):
class HadisCorrection(models.Model):
hadis = models.ForeignKey(Hadis, verbose_name=_("hadis correction"), on_delete=models.CASCADE)
title = models.CharField(max_length=255, verbose_name=_("title"))
description = models.TextField(verbose_name=_("description"), blank=True, null=True)
title = models.JSONField(default = list , verbose_name=_('Title'))
description =models.JSONField(default = list , verbose_name=_('Description'))
translation = models.JSONField(verbose_name=_("translation"), default=list)
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("created at"))
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("updated at"))

16
apps/hadis/models/reference.py

@ -8,15 +8,15 @@ class BookReference(models.Model):
Model for hadis book references with detailed information
This is different from library books - these are reference books for hadis
"""
title = models.CharField(max_length=500, verbose_name=_('title'))
description = models.TextField(verbose_name=_('description'), blank=True, null=True)
language = models.CharField(max_length=100, verbose_name=_('language'), blank=True, null=True)
title = models.JSONField(default = list , verbose_name=_('Title'))
description = models.JSONField(default = list , verbose_name=_('Description'))
language = models.JSONField(default = list , verbose_name=_('Language'))
isbn = models.CharField(max_length=100, verbose_name=_('ISBN'), blank=True, null=True)
volume = models.CharField(max_length=100, verbose_name=_('volume'), blank=True, null=True)
year_of_publication = models.CharField(max_length=50, verbose_name=_('year of publication'), blank=True, null=True)
number_page = models.PositiveIntegerField(verbose_name=_('number of pages'), blank=True, null=True)
slug = models.SlugField(max_length=255, verbose_name=_('slug'), blank=True,unique=True)
publisher = models.TextField(verbose_name=_('publisher'),blank=True,null=True)
publisher = models.JSONField(default = list , verbose_name=_('Publisher'))
rate = models.DecimalField(
max_digits=3,
decimal_places=2,
@ -60,7 +60,7 @@ class BookReferenceImage(models.Model):
)
image = models.ImageField(upload_to='hadis/book_reference_images/', verbose_name=_('image'))
order = models.PositiveIntegerField(default=0, verbose_name=_('order'))
description = models.CharField(max_length=255, verbose_name=_('description'), blank=True, null=True)
description = models.JSONField(default = list , verbose_name=_('Description'))
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'))
@ -77,7 +77,7 @@ class BookAuthor(models.Model):
"""
Model for book reference authors
"""
name = models.CharField(max_length=255, verbose_name=_('name'))
name = models.JSONField(default = list , verbose_name=_('Name'))
book_references = models.ManyToManyField(
BookReference,
related_name='authors',
@ -101,8 +101,8 @@ class BookAttribute(models.Model):
"""
Model for book reference attributes - custom key-value pairs
"""
title = models.CharField(max_length=255, verbose_name=_('title'))
value = models.CharField(max_length=500, verbose_name=_('value'))
title = models.JSONField(default = list , verbose_name=_('Title'))
value = models.JSONField(default = list , verbose_name=_('Value'))
book_reference = models.ForeignKey(
BookReference,
on_delete=models.CASCADE,

35
apps/hadis/models/transmitter.py

@ -12,9 +12,9 @@ class NarratorLayer(models.Model):
Model for narrator layers/classes (Tabaqat)
Represents the classification level of narrators in hadis chains
"""
name = models.CharField(max_length=255, verbose_name=_('name'))
name = models.JSONField(default = list , verbose_name=_('Name'))
number = models.PositiveIntegerField(verbose_name=_('layer number'), unique=True)
description = models.TextField(verbose_name=_('description'), blank=True, null=True)
description = models.JSONField(default = list , verbose_name=_('Description'))
slug = models.SlugField(max_length=255,unique=True, verbose_name=_('slug'), blank=True)
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'))
@ -55,16 +55,16 @@ class Transmitters(models.Model):
UNKNOWN = 'unknown', _('Unknown')
# Basic Information
full_name = models.CharField(max_length=255, verbose_name=_('full name'))
kunya = models.CharField(max_length=255, verbose_name=_('Kunya'), blank=True, null=True, help_text=_('e.g., Abu Abdullah'))
known_as = models.CharField(max_length=255, verbose_name=_('Known As'), blank=True, null=True)
nickname = models.CharField(max_length=255, verbose_name=_('Nickname/Laqab'), blank=True, null=True)
full_name = models.JSONField(default = list , verbose_name=_('Full Name'))
kunya = models.JSONField(default = list , verbose_name=_('Kunya'))
known_as = models.JSONField(default = list , verbose_name=_('Known as'))
nickname = models.JSONField(default = list , verbose_name=_('Nick Name'))
slug = models.SlugField(max_length=255, verbose_name=_('slug'), blank=True,unique=True)
# Geographic Information
origin = models.CharField(max_length=255, verbose_name=_('Origin'), blank=True, null=True, help_text=_('Place of origin'))
lived_in = models.CharField(max_length=255, verbose_name=_('Lived In'), blank=True, null=True, help_text=_('Places where they lived'))
died_in = models.CharField(max_length=255, verbose_name=_('Died In'), blank=True, null=True, help_text=_('Place of death'))
origin = models.JSONField(default = list , verbose_name=_('Origin'))
lived_in = models.JSONField(default = list , verbose_name=_('Lived in'))
died_in = models.JSONField(default = list , verbose_name=_('Died in'))
# Date Information
birth_year_hijri = models.IntegerField(verbose_name=_("Birth Year (Hijri)"), null=True, blank=True)
@ -98,7 +98,7 @@ class Transmitters(models.Model):
)
# Additional Information
description = models.TextField(blank=True, null=True, verbose_name=_("Description"))
description = models.JSONField(default = list , verbose_name=_('Description'))
thumbnail = FilerImageField(
related_name="+",
on_delete=models.CASCADE,
@ -200,15 +200,8 @@ class TransmitterOpinion(models.Model):
verbose_name=_('transmitter'),
related_name='opinions'
)
scholar_name = models.CharField(
max_length=255,
verbose_name=_('Scholar Name'),
help_text=_('Name of the scholar who gave this opinion')
)
opinion_text = models.TextField(
verbose_name=_('Opinion Text'),
help_text=_('The scholar\'s opinion about this transmitter')
)
scholar_name = models.JSONField(default = list , verbose_name=_('Scholar Name'))
opinion_text = models.JSONField(default = list , verbose_name=_('Opinion Text'))
status = models.CharField(
max_length=20,
choices=OpinionStatus.choices,
@ -235,8 +228,8 @@ class TransmitterOriginalText(models.Model):
verbose_name=_('transmitter'),
related_name='originaltexts'
)
title = models.CharField(max_length=255, verbose_name=_('title'), null=True, blank=True)
text = models.TextField(verbose_name=_('text'))
title = models.JSONField(default = list , verbose_name=_('Title'))
text = models.JSONField(default = list , verbose_name=_('Text'))
translation = models.JSONField(verbose_name=_('translation'), default=list)
share_link = models.CharField(max_length=255, verbose_name=_('share link'), null=True, blank=True)

1
apps/hadis/serializers/category.py

@ -206,3 +206,4 @@ class CategorySerializer(serializers.ModelSerializer):
def get_hadis_count(self,obj):
return len(Hadis.objects.filter(category=obj))

9
apps/hadis/serializers/hadis.py

@ -149,6 +149,7 @@ class HadisListSerializer(serializers.ModelSerializer):
"""Serializer for Hadis list"""
category = serializers.SerializerMethodField()
translation = serializers.SerializerMethodField()
title = serializers.SerializerMethodField()
class Meta:
model = Hadis
@ -173,6 +174,14 @@ class HadisListSerializer(serializers.ModelSerializer):
language_code = getattr(request, 'LANGUAGE_CODE', 'en')
return obj.translation.get(language_code)
def get_title(self,obj):
# ✅ Get language from request
request = self.context.get('request')
lang = request.query_params.get('lang', 'ru') if request else 'ru'
# ✅ CALL THE MODEL METHOD!
return obj.get_title(lang)
class HadisStatusSerializer(serializers.ModelSerializer):
"""Serializer for HadisStatus"""

Loading…
Cancel
Save