Browse Source

Enhance Hadis model and serializers with new fields and data handling

- Added 'explanations' and 'address_details' JSON fields to the Hadis model for improved data structure.
- Updated HadisAdminForm to include new fields in the admin interface.
- Introduced a new management command for comprehensive seeding of Hadis data, including Russian language support.
- Enhanced serializers to process and return structured explanations and address details based on request language.
- Updated entrypoint script to include the new data seeding command during initialization.
master
mortezaei 4 months ago
parent
commit
9b0a8044a6
  1. 65
      apps/hadis/admin/hadis.py
  2. 602
      apps/hadis/management/commands/seed_complete_hadis_data.py
  3. 9
      apps/hadis/models/hadis.py
  4. 57
      apps/hadis/serializers/hadis.py
  5. 6
      entrypoint.sh

65
apps/hadis/admin/hadis.py

@ -75,6 +75,57 @@ class HadisAdminForm(forms.ModelForm):
}
}
# 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),
@ -86,6 +137,16 @@ class HadisAdminForm(forms.ModelForm):
'title': 'Links'
})
self.fields['explanations'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(explanations_schema),
'title': 'Explanations'
})
self.fields['address_details'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(address_details_schema),
'title': 'Address Details'
})
# Inline Admin Classes
class ReferenceImageInline(TabularInline):
@ -153,13 +214,13 @@ class HadisAdmin(ModelAdmin):
'fields': ('category', 'number', 'title', 'status')
}),
(_('Content'), {
'fields': ('text', 'translation', 'explanation')
'fields': ('text', 'translation', 'explanation', 'explanations')
}),
(_('Status & Classification'), {
'fields': ('hadis_status', 'hadis_status_text', 'tags')
}),
(_('Additional Information'), {
'fields': ('address', 'links', 'share_link'),
'fields': ('address', 'address_details', 'links', 'share_link'),
'classes': ('collapse',)
}),
(_('Timestamps'), {

602
apps/hadis/management/commands/seed_complete_hadis_data.py

@ -0,0 +1,602 @@
"""
Comprehensive fake data generation script for all Hadis-related models.
Generates Russian language data for all existing Hadis and creates 100 new complete Hadis records.
Usage:
python manage.py seed_complete_hadis_data
"""
import random
from django.core.management.base import BaseCommand
from django.db import transaction
from django.db import models
from apps.hadis.models import (
Hadis, HadisCategory, HadisSect, HadisStatus, HadisTag,
HadisReference, ReferenceImage, HadisCollection, HadisInCollection,
HadisCorrection, HadisTransmitter, Transmitters, NarratorLayer,
TransmitterReliability, OpinionStatus, TransmitterOpinion,
TransmitterOriginalText, BookReference, BookAuthor
)
# ============================================================================
# RUSSIAN DATA TEMPLATES
# ============================================================================
RUSSIAN_TRANSMITTER_NAMES = [
"Абу Абдуллах Мухаммад", "Али ибн Хусейн", "Хасан ибн Али",
"Мухаммад ибн Якуб", "Ахмад ибн Ханбал", "Малик ибн Анас",
"Абу Ханифа Нуман", "Мухаммад аш-Шафии", "Абу Бакр ас-Сиддик",
"Умар ибн аль-Хаттаб", "Усман ибн Аффан", "Джафар ас-Садик",
"Муса аль-Казим", "Али ар-Рида", "Мухаммад ат-Таки",
"Хасан аль-Аскари", "Фатима Захра", "Зейнаб бинт Али",
"Абдуллах ибн Аббас", "Анас ибн Малик", "Абу Хурайра",
"Аиша бинт Абу Бакр", "Салман аль-Фариси", "Биляль аль-Хабаши",
"Халид ибн Валид", "Саад ибн Аби Ваккас", "Амр ибн аль-Ас",
"Зейд ибн Харис", "Абу Убайда ибн аль-Джаррах", "Тальха ибн Убайдуллах"
]
RUSSIAN_KUNYA = [
"Абу Мухаммад", "Абу Али", "Абу Хасан", "Абу Бакр",
"Абу Умар", "Абу Абдуллах", "Абу Джафар", "Абу Муса",
"Абу Саид", "Абу Зарр", "Умм Салама", "Умм Кульсум"
]
RUSSIAN_ORIGINS = [
"Медина", "Мекка", "Куфа", "Басра", "Багдад", "Дамаск",
"Каир", "Кордова", "Бухара", "Самарканд", "Найсабур",
"Рей", "Ширас", "Исфахан", "Хорасан"
]
RUSSIAN_RELIABILITY_LEVELS = [
{"title": "Очень надежный", "slug": "very-reliable", "color": "green"},
{"title": "Надежный", "slug": "reliable", "color": "blue"},
{"title": "Приемлемый", "slug": "acceptable", "color": "yellow"},
{"title": "Слабый", "slug": "weak", "color": "orange"},
{"title": "Очень слабый", "slug": "very-weak", "color": "red"},
{"title": "Неизвестный", "slug": "unknown", "color": "gray"},
{"title": "Заслуживающий доверия", "slug": "trustworthy", "color": "green"},
]
RUSSIAN_HADIS_STATUSES = [
{"title": "Достоверный", "slug": "sahih", "color": "green"},
{"title": "Хороший", "slug": "hasan", "color": "blue"},
{"title": "Слабый", "slug": "daif", "color": "orange"},
{"title": "Выдуманный", "slug": "mawdu", "color": "red"},
{"title": "Подтвержденный", "slug": "confirmed", "color": "green"},
]
RUSSIAN_TAGS = [
"Молитва", "Пост", "Знание", "Терпение", "Справедливость",
"Милосердие", "Благочестие", "Семья", "Воспитание", "Покаяние",
"Благодарность", "Смирение", "Честность", "Доброта", "Мудрость",
"Вера", "Надежда", "Любовь", "Мир", "Истина"
]
RUSSIAN_HADIS_OPENINGS = [
"Пророк (мир ему) сказал:",
"Имам Али (мир ему) сказал:",
"Имам Джафар ас-Садик (мир ему) сказал:",
"Имам Хусейн (мир ему) сказал:",
"Передается от Пророка (мир ему):",
"Рассказывает имам Бакир (мир ему):",
"Сообщается от имама Казима (мир ему):",
"Имам Риза (мир ему) сказал:",
]
RUSSIAN_HADIS_BODIES = [
"Лучший из вас тот, кто учится и учит других.",
"Ищите знания от колыбели до могилы.",
"Терпение - ключ к облегчению.",
"Молитва - столп религии.",
"Знание - свет для сердца.",
"Доброта к родителям - обязанность верующего.",
"Справедливость - основа власти.",
"Правда ведет к благочестию.",
"Смирение возвышает человека.",
"Благодарность увеличивает благословения.",
"Прощение - признак силы.",
"Терпение приносит награду.",
"Вера укрепляется добрыми делами.",
"Знание без действия бесполезно.",
"Лучшее богатство - довольство.",
"Самый сильный - тот, кто владеет собой в гневе.",
"Сосед имеет права на тебя.",
"Улыбка - это милостыня.",
"Чистота - половина веры.",
"Намерение определяет ценность дела.",
"Мудрость - потерянное сокровище верующего.",
"Лучший джихад - борьба с собственной душой.",
"Рай находится под ногами матерей.",
"Молчание - мудрость, но мало кто молчит.",
"Верующий не кусает дважды из одной норы.",
]
RUSSIAN_HADIS_TITLES = [
"О терпении и награде", "О знании и мудрости", "О молитве и поклонении",
"О справедливости и праведности", "О семье и воспитании",
"О доброте и милосердии", "О вере и благочестии", "О покаянии и прощении",
"О благодарности Аллаху", "О смирении и скромности", "О правде и честности",
"О соседях и обществе", "О торговле и справедливости",
"О чистоте и гигиене", "О намерении и искренности", "О любви к Пророку",
"О следовании сунне", "О важности молитвы", "О посте и его пользе",
"О закяте и милостыне", "О паломничестве", "О борьбе с нафсом",
]
RUSSIAN_BOOK_TITLES = [
"Основы веры", "Путь праведных", "Свет истины", "Книга знания",
"Сады праведников", "Сокровища мудрости", "Источник благочестия",
"Ключи к раю", "Путеводитель верующих", "Книга о молитве",
"Собрание хадисов", "Энциклопедия ислама", "Наставления имамов",
"Мудрость пророков", "Книга о терпении", "Путь к совершенству",
"Духовные сокровища", "Книга о справедливости", "Свет веры",
"Драгоценности знания"
]
RUSSIAN_AUTHOR_NAMES = [
"Шейх Мухаммад аль-Кулайни", "Имам ан-Навави", "Ибн Хаджар аль-Аскаляни",
"Имам аль-Бухари", "Имам Муслим", "Абу Дауд", "Ат-Тирмизи",
"Ибн Маджа", "Ахмад ибн Ханбал", "Имам Малик", "Имам аш-Шафии",
"Аллама Маджлиси", "Шейх Муфид", "Шейх Туси", "Алламе Хилли",
"Сайид Муртаза", "Шейх Садук", "Мирза Мухаммад Таги",
"Аятолла Хои", "Аятолла Систани"
]
RUSSIAN_NARRATOR_LAYERS = [
{"number": 1, "name": "Сподвижники Пророка", "description": "Первое поколение - сподвижники Пророка Мухаммада (мир ему)"},
{"number": 2, "name": "Табиин", "description": "Второе поколение - последователи сподвижников"},
{"number": 3, "name": "Таба табиин", "description": "Третье поколение - последователи последователей"},
{"number": 4, "name": "Четвертое поколение", "description": "Четвертое поколение передатчиков"},
{"number": 5, "name": "Пятое поколение", "description": "Пятое поколение передатчиков"},
{"number": 6, "name": "Шестое поколение", "description": "Шестое поколение передатчиков"},
{"number": 7, "name": "Седьмое поколение", "description": "Седьмое поколение передатчиков"},
{"number": 8, "name": "Восьмое поколение", "description": "Восьмое поколение передатчиков"},
]
RUSSIAN_SCHOLAR_NAMES = [
"Имам ан-Навави", "Ибн Хаджар", "Аз-Захаби", "Ибн Хиббан",
"Яхья ибн Маин", "Ахмад ибн Ханбал", "Али ибн аль-Мадини",
"Абу Хатим ар-Рази", "Имам аль-Бухари", "Имам Муслим"
]
RUSSIAN_OPINIONS = [
"Надежный передатчик, заслуживающий доверия",
"Слабый в передаче, но правдивый",
"Очень точный и надежный рассказчик",
"Сомнительный передатчик, следует проявлять осторожность",
"Выдающийся ученый своего времени",
"Известен своей памятью и точностью",
"Слабый в некоторых передачах",
"Заслуживающий доверия, но делает ошибки",
]
RUSSIAN_OPINION_STATUSES = [
{"title": "Подтвержденный", "slug": "confirmed", "color": "green"},
{"title": "Смешанный", "slug": "mixed", "color": "yellow"},
{"title": "Отклоненный", "slug": "rejected", "color": "red"},
]
RUSSIAN_COLLECTION_NAMES = [
"Молитва и поклонение", "Знание и мудрость", "Семья и воспитание",
"Справедливость и права", "Терпение и благодарность",
"Покаяние и прощение", "Любовь и милосердие", "Социальные отношения",
"Торговля и экономика", "Духовное очищение"
]
RUSSIAN_ADDRESSES = [
"Аль-Кафи, том 2, глава 3, хадис 15",
"Сахих аль-Бухари, книга веры, хадис 52",
"Сахих Муслим, книга молитвы, хадис 125",
"Сунан Абу Дауд, книга чистоты, хадис 87",
"Джами ат-Тирмизи, книга знания, хадис 45",
"Муснад Ахмад, том 3, страница 245",
"Бихар аль-Анвар, том 75, страница 123",
]
class Command(BaseCommand):
help = 'Generate comprehensive fake data for all Hadis-related models in Russian'
def __init__(self):
super().__init__()
self.created_counts = {}
self.reliability_statuses = []
self.opinion_statuses = []
self.narrator_layers = []
self.transmitters = []
self.books = []
self.authors = []
self.categories = []
self.hadis_statuses = []
self.tags = []
def handle(self, *args, **options):
self.stdout.write(self.style.SUCCESS('Starting comprehensive Hadis data generation...'))
try:
with transaction.atomic():
# Phase 1: Foundation
self.stdout.write('Phase 1: Creating foundation data...')
self.create_sects_and_categories()
# Phase 2: Supporting models
self.stdout.write('Phase 2: Creating supporting models...')
self.create_statuses_and_tags()
# Phase 3: Narrator infrastructure
self.stdout.write('Phase 3: Creating narrator infrastructure...')
self.create_narrator_layers()
self.create_reliability_statuses()
self.create_opinion_statuses()
# Phase 4: Transmitters
self.stdout.write('Phase 4: Creating transmitters...')
self.create_transmitters(count=250)
# Phase 5: Books and authors
self.stdout.write('Phase 5: Creating books and authors...')
self.create_books_and_authors()
# Phase 6: Populate existing hadiths
self.stdout.write('Phase 6: Populating existing hadiths...')
self.populate_existing_hadiths()
# Phase 7: Create new hadiths
self.stdout.write('Phase 7: Creating new hadiths...')
self.create_new_hadiths(count=100)
# Phase 8: Create collections
self.stdout.write('Phase 8: Creating collections...')
self.create_collections()
# Phase 9: Create corrections
self.stdout.write('Phase 9: Creating corrections...')
self.create_corrections()
# Summary
self.print_summary()
except Exception as e:
self.stdout.write(self.style.ERROR(f'Error: {str(e)}'))
raise
def create_sects_and_categories(self):
"""Create or get existing sects and categories"""
# Get existing categories
self.categories = list(HadisCategory.objects.all()[:10])
if not self.categories:
# Create a default category if none exist
sect, _ = HadisSect.objects.get_or_create(
sect_type='shia',
defaults={'title': [{'language_code': 'ru', 'text': 'Шиизм'}]}
)
category = HadisCategory.objects.create(
title=[{'language_code': 'ru', 'text': 'Общие хадисы'}],
sect=sect,
source_type='hadith'
)
self.categories.append(category)
self.created_counts['categories'] = len(self.categories)
def create_statuses_and_tags(self):
"""Create hadis statuses and tags"""
# Create statuses
for status_data in RUSSIAN_HADIS_STATUSES:
status, created = HadisStatus.objects.get_or_create(
slug=status_data['slug'],
defaults={
'title': [{'language_code': 'ru', 'text': status_data['title']}],
'color': status_data['color'],
'order': len(self.hadis_statuses)
}
)
self.hadis_statuses.append(status)
# Create tags
for i, tag_name in enumerate(RUSSIAN_TAGS):
tag, created = HadisTag.objects.get_or_create(
title__0__text=tag_name,
defaults={
'title': [{'language_code': 'ru', 'text': tag_name}],
'status': True
}
)
if created:
self.tags.append(tag)
# Get existing tags if we didn't create enough
if len(self.tags) < 5:
self.tags = list(HadisTag.objects.all()[:20])
self.created_counts['statuses'] = len(self.hadis_statuses)
self.created_counts['tags'] = len(self.tags)
def create_narrator_layers(self):
"""Create narrator layers"""
for layer_data in RUSSIAN_NARRATOR_LAYERS:
layer, created = NarratorLayer.objects.get_or_create(
number=layer_data['number'],
defaults={
'name': [{'language_code': 'ru', 'text': layer_data['name']}],
'description': [{'language_code': 'ru', 'text': layer_data['description']}]
}
)
self.narrator_layers.append(layer)
self.created_counts['narrator_layers'] = len(self.narrator_layers)
def create_reliability_statuses(self):
"""Create transmitter reliability statuses"""
for reliability_data in RUSSIAN_RELIABILITY_LEVELS:
reliability, created = TransmitterReliability.objects.get_or_create(
slug=reliability_data['slug'],
defaults={
'title': [{'language_code': 'ru', 'text': reliability_data['title']}],
'color': reliability_data['color']
}
)
self.reliability_statuses.append(reliability)
self.created_counts['reliability_statuses'] = len(self.reliability_statuses)
def create_opinion_statuses(self):
"""Create opinion statuses"""
for opinion_data in RUSSIAN_OPINION_STATUSES:
opinion_status, created = OpinionStatus.objects.get_or_create(
slug=opinion_data['slug'],
defaults={
'title': [{'language_code': 'ru', 'text': opinion_data['title']}],
'color': opinion_data['color']
}
)
self.opinion_statuses.append(opinion_status)
self.created_counts['opinion_statuses'] = len(self.opinion_statuses)
def create_transmitters(self, count=250):
"""Create transmitters with full biographical data"""
for i in range(count):
name = random.choice(RUSSIAN_TRANSMITTER_NAMES)
kunya = random.choice(RUSSIAN_KUNYA)
origin = random.choice(RUSSIAN_ORIGINS)
# Random dates
birth_year = random.randint(1, 300)
death_year = birth_year + random.randint(40, 90)
age = death_year - birth_year
transmitter = Transmitters.objects.create(
full_name=[{'language_code': 'ru', 'text': f"{name} ибн {random.choice(RUSSIAN_TRANSMITTER_NAMES.split()[0] if ' ' in random.choice(RUSSIAN_TRANSMITTER_NAMES) else 'Абдуллах')}"}],
kunya=[{'language_code': 'ru', 'text': kunya}],
known_as=[{'language_code': 'ru', 'text': f"{name} {origin}ский"}],
nickname=[{'language_code': 'ru', 'text': f"{random.choice(['аль-Муфассир', 'аль-Хафиз', 'аль-Факих', 'аль-Мухаддис'])}"}],
origin=[{'language_code': 'ru', 'text': origin}],
lived_in=[{'language_code': 'ru', 'text': random.choice(RUSSIAN_ORIGINS)}],
died_in=[{'language_code': 'ru', 'text': random.choice(RUSSIAN_ORIGINS)}],
birth_year_hijri=birth_year,
death_year_hijri=death_year,
age_at_death=age,
generation=random.randint(1, 8),
reliability=random.choice(self.reliability_statuses),
madhhab=random.choice(['shia', 'sunni', 'hanafi', 'maliki', 'shafii']),
in_sahih_muslim=random.choice([True, False]),
in_sahih_bukhari=random.choice([True, False]),
description=[{
'language_code': 'ru',
'text': f"{name} был известным передатчиком хадисов из {origin}. Он изучал знания у великих ученых своего времени и передал множество достоверных хадисов."
}]
)
self.transmitters.append(transmitter)
# Add opinions for some transmitters
if random.random() > 0.5:
for _ in range(random.randint(1, 3)):
TransmitterOpinion.objects.create(
transmitter=transmitter,
scholar_name=[{'language_code': 'ru', 'text': random.choice(RUSSIAN_SCHOLAR_NAMES)}],
opinion_text=[{'language_code': 'ru', 'text': random.choice(RUSSIAN_OPINIONS)}],
status=random.choice(self.opinion_statuses) if self.opinion_statuses else None
)
# Add original texts for some transmitters
if random.random() > 0.7:
TransmitterOriginalText.objects.create(
transmitter=transmitter,
title=[{'language_code': 'ru', 'text': f"Текст от {name}"}],
text=[{'language_code': 'ru', 'text': random.choice(RUSSIAN_HADIS_BODIES)}],
translation=[{'language_code': 'ru', 'text': random.choice(RUSSIAN_HADIS_BODIES)}]
)
self.created_counts['transmitters'] = count
def create_books_and_authors(self):
"""Create books and authors"""
# Create authors
for author_name in RUSSIAN_AUTHOR_NAMES[:15]:
author = BookAuthor.objects.create(
name=[{'language_code': 'ru', 'text': author_name}],
slug=None # Will be auto-generated
)
self.authors.append(author)
# Create books
for book_title in RUSSIAN_BOOK_TITLES[:20]:
book = BookReference.objects.create(
title=[{'language_code': 'ru', 'text': book_title}],
description=f"Классическое исламское произведение - {book_title}",
slug=None # Will be auto-generated
)
# Add random authors
book.authors.add(*random.sample(self.authors, random.randint(1, 2)))
self.books.append(book)
self.created_counts['authors'] = len(self.authors)
self.created_counts['books'] = len(self.books)
def populate_existing_hadiths(self):
"""Populate all existing hadiths with related data"""
existing_hadiths = Hadis.objects.all()
count = 0
for hadis in existing_hadiths:
self._populate_hadis_relations(hadis)
count += 1
self.created_counts['existing_hadiths_populated'] = count
def create_new_hadiths(self, count=100):
"""Create new complete hadiths"""
max_number = Hadis.objects.aggregate(models.Max('number'))['number__max'] or 0
for i in range(count):
hadis = Hadis.objects.create(
category=random.choice(self.categories) if self.categories else None,
number=max_number + i + 1,
title=[{'language_code': 'ru', 'text': random.choice(RUSSIAN_HADIS_TITLES)}],
title_narrator=[{'language_code': 'ru', 'text': f"Передано от {random.choice(RUSSIAN_TRANSMITTER_NAMES)}"}],
description=[{
'language_code': 'ru',
'text': f"Этот хадис о важности {random.choice(['молитвы', 'знания', 'терпения', 'справедливости'])} в жизни верующего."
}],
text=f"{random.choice(RUSSIAN_HADIS_OPENINGS)} {random.choice(RUSSIAN_HADIS_BODIES)}",
translation=[{
'language_code': 'ru',
'text': f"{random.choice(RUSSIAN_HADIS_OPENINGS)} {random.choice(RUSSIAN_HADIS_BODIES)}"
}],
status=True,
hadis_status=random.choice(self.hadis_statuses) if self.hadis_statuses else None,
hadis_status_text=[{
'language_code': 'ru',
'text': f"Этот хадис классифицирован как {random.choice(['достоверный', 'хороший', 'слабый'])} согласно критериям ученых."
}],
address=[{
'language_code': 'ru',
'text': random.choice(RUSSIAN_ADDRESSES)
}],
explanation=[{
'language_code': 'ru',
'text': f"Этот хадис учит нас о важности {random.choice(['веры', 'знания', 'терпения', 'благочестия'])} в нашей повседневной жизни."
}],
explanations=[
{
'language_code': 'ru',
'title': 'Контекст хадиса',
'description': 'Этот хадис был передан в контексте обучения сподвижников основам ислама и праведного поведения.'
},
{
'language_code': 'ru',
'title': 'Практическое применение',
'description': 'Верующие должны применять это учение в своей повседневной жизни через добрые дела и праведное поведение.'
}
],
address_details=[
{
'text': random.choice(RUSSIAN_ADDRESSES),
'priority': 1
},
{
'text': f"Также упоминается в {random.choice(RUSSIAN_BOOK_TITLES)}",
'priority': 2
}
],
links={'video': f'https://example.com/hadis/{max_number + i + 1}'}
)
# Add tags
hadis.tags.add(*random.sample(self.tags, random.randint(2, 5)))
# Populate relations
self._populate_hadis_relations(hadis)
self.created_counts['new_hadiths'] = count
def _populate_hadis_relations(self, hadis):
"""Populate all relations for a hadis"""
# Add transmitters (chain of narration)
chain_length = random.randint(3, 7)
for order in range(chain_length):
HadisTransmitter.objects.get_or_create(
hadis=hadis,
transmitter=random.choice(self.transmitters),
order=order,
defaults={
'narrator_layer': random.choice(self.narrator_layers) if self.narrator_layers else None,
'status': random.choice(self.reliability_statuses) if self.reliability_statuses else None,
'is_gap': random.choice([True, False]) if order > 0 else False
}
)
# Add references
for _ in range(random.randint(1, 3)):
ref, created = HadisReference.objects.get_or_create(
hadis=hadis,
book_reference=random.choice(self.books) if self.books else None,
defaults={
'description': [{
'language_code': 'ru',
'text': f"Ссылка на {random.choice(RUSSIAN_BOOK_TITLES)}"
}]
}
)
def create_collections(self):
"""Create hadis collections"""
all_hadiths = list(Hadis.objects.all())
for collection_name in RUSSIAN_COLLECTION_NAMES[:10]:
collection = HadisCollection.objects.create(
title=[{'language_code': 'ru', 'text': collection_name}],
summary=[{
'language_code': 'ru',
'text': f"Коллекция хадисов о {collection_name.lower()}"
}],
status=True,
order=len(self.created_counts.get('collections', []))
)
# Add random hadiths to collection
selected_hadiths = random.sample(all_hadiths, min(random.randint(5, 15), len(all_hadiths)))
for order, hadis in enumerate(selected_hadiths):
HadisInCollection.objects.create(
hadis=hadis,
collection=collection,
order=order
)
self.created_counts['collections'] = len(RUSSIAN_COLLECTION_NAMES[:10])
def create_corrections(self):
"""Create corrections for some hadiths"""
all_hadiths = list(Hadis.objects.all()[:50]) # Only first 50
count = 0
for hadis in random.sample(all_hadiths, min(20, len(all_hadiths))):
if random.random() > 0.6: # 40% chance
HadisCorrection.objects.create(
hadis=hadis,
title=[{'language_code': 'ru', 'text': f"Исправление к хадису {hadis.number}"}],
description=[{
'language_code': 'ru',
'text': "Уточнение цепочки передатчиков и текста хадиса на основе дополнительных источников."
}],
translation=[{
'language_code': 'ru',
'text': f"Исправленный перевод: {random.choice(RUSSIAN_HADIS_BODIES)}"
}]
)
count += 1
self.created_counts['corrections'] = count
def print_summary(self):
"""Print summary of created data"""
self.stdout.write(self.style.SUCCESS('\n' + '='*60))
self.stdout.write(self.style.SUCCESS('DATA GENERATION COMPLETE'))
self.stdout.write(self.style.SUCCESS('='*60))
for key, value in self.created_counts.items():
self.stdout.write(f"{key.replace('_', ' ').title()}: {value}")
self.stdout.write(self.style.SUCCESS('='*60 + '\n'))

9
apps/hadis/models/hadis.py

@ -192,6 +192,8 @@ class Hadis(models.Model):
share_link = models.CharField(max_length=255, verbose_name=_('share link'), null=True, blank=True)
explanation = models.JSONField(default = list , verbose_name=_('Explanation'))
explanations = models.JSONField(default = list , verbose_name=_('Explanations'))
address_details = models.JSONField(default = list , verbose_name=_('Address Details'))
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'))
updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at'))
@ -293,6 +295,13 @@ class Hadis(models.Model):
def get_explanation(self, lang):
return self._get_json_field("explanation" , lang)
def get_explanations(self, lang):
return self._get_json_field("explanations" , lang)
def get_address_details(self, lang):
"""Get address details (returns full list, not localized)"""
return self.address_details if self.address_details else []
def save(self, *args, **kwargs):
# ساخت share_link قبل از ذخیره
if not self.share_link:

57
apps/hadis/serializers/hadis.py

@ -99,8 +99,17 @@ class HadisSyncSerializer(serializers.ModelSerializer):
'priority': img.priority,
})
# Process address_details
address_details_list = []
if obj.address_details and isinstance(obj.address_details, list):
address_details_list = sorted(
obj.address_details,
key=lambda x: x.get('priority', 0)
)
return {
'address': get_localized_text(obj.address, request),
'address_details': address_details_list,
'hadis_status': status_block,
'status_text': get_localized_text(obj.hadis_status_text, request),
'share_link': obj.share_link,
@ -138,7 +147,25 @@ class HadisSyncSerializer(serializers.ModelSerializer):
def get_explanations(self, obj):
request = self.context.get('request')
return get_localized_text(obj.explanation, request)
# Return structured explanations with title and description
explanations_list = []
if obj.explanations and isinstance(obj.explanations, list):
for item in obj.explanations:
if isinstance(item, dict):
lang = item.get('language_code')
# Check if matches request language
request_lang = request.query_params.get('lang', 'en') if request else 'en'
if lang == request_lang:
explanations_list.append({
'title': item.get('title', ''),
'description': item.get('description', '')
})
# If no match, return first available or fallback to old explanation field
if not explanations_list and obj.explanation:
return get_localized_text(obj.explanation, request)
return explanations_list if explanations_list else None
def get_corrections(self, obj):
request = self.context.get('request')
@ -591,14 +618,31 @@ class HadisBasicSerializer(serializers.ModelSerializer):
title = LocalizedField()
title_narrator = LocalizedField()
explanation = LocalizedField()
explanations = serializers.SerializerMethodField()
class Meta:
model = Hadis
fields = [
'id', 'slug', 'title','bookmark', 'title_narrator', 'text',
'translation', 'share_link','explanation','category'
'translation', 'share_link','explanation', 'explanations','category'
]
def get_explanations(self, obj):
"""Get structured explanations for the requested language"""
request = self.context.get('request')
request_lang = request.query_params.get('lang', 'en') if request else 'en'
explanations_list = []
if obj.explanations and isinstance(obj.explanations, list):
for item in obj.explanations:
if isinstance(item, dict) and item.get('language_code') == request_lang:
explanations_list.append({
'title': item.get('title', ''),
'description': item.get('description', '')
})
return explanations_list if explanations_list else None
def get_category(self, obj):
"""Get category id and title"""
@ -650,14 +694,21 @@ class HadisDetailSerializer(serializers.ModelSerializer):
)
reference_images = SerializerMethodField()
address = LocalizedField()
address_details = serializers.SerializerMethodField()
class Meta:
model = Hadis
fields = [
'id', 'number', 'slug','hadis_status', 'links','share_link',
'tags','references','reference_images','address'
'tags','references','reference_images','address', 'address_details'
]
def get_address_details(self, obj):
"""Get address details sorted by priority"""
if obj.address_details and isinstance(obj.address_details, list):
return sorted(obj.address_details, key=lambda x: x.get('priority', 0))
return []
def get_reference_images(self, obj):
"""Get all reference images from all references"""
all_images = []

6
entrypoint.sh

@ -1,14 +1,14 @@
#!/bin/sh
sleep 20
python manage.py makemigrations hadis
python manage.py migrate
# python manage.py seed_images
python manage.py collectstatic --noinput
# Seed Russian data (only runs once, skips if data exists)
# python manage.py seed_russian_data
python manage.py hadisreferences
# python manage.py hadisreferences
python manage.py seed_complete_hadis_data
# python manage.py populate_books
# python manage.py populate_book_reference
# python manage.py populate_refrence_images

Loading…
Cancel
Save