Browse Source

Migrations temporary fixed .

update hadis transmitters seeding.
master
Mohsen Taba 4 months ago
parent
commit
88bbef83a7
  1. 2
      apps/chat/migrations/0002_auto_20241125_1219.py
  2. 132
      apps/course/migrations/0004_alter_attachment_options_alter_glossary_options_and_more.py
  3. 42
      apps/course/migrations/0004_auto_20241122_1913.py
  4. 2
      apps/course/migrations/0005_add_database_indexes.py
  5. 2
      apps/course/migrations/0005_participant_unread_messages_count.py
  6. 82
      apps/hadis/management/commands/seed_hadis_transmitter.py
  7. 218
      apps/hadis/management/commands/seed_transmitters.py
  8. 4
      apps/hadis/models/hadis.py
  9. 8
      apps/hadis/models/transmitter.py
  10. 44
      apps/hadis/serializers/hadis.py
  11. 3
      entrypoint.sh

2
apps/chat/migrations/0002_auto_20241125_1219.py

@ -8,7 +8,7 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('course', '0004_auto_20241122_1913'),
('course', '0003_alter_course_is_online_alter_course_timing_and_more'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('chat', '0001_initial'), ('chat', '0001_initial'),
] ]

132
apps/course/migrations/0004_alter_attachment_options_alter_glossary_options_and_more.py

@ -1,132 +0,0 @@
# Generated by Django 5.1.8 on 2025-04-13 01:35
import django.db.models.deletion
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0002_alter_user_phone_number'),
('course', '0003_alter_course_is_online_alter_course_timing_and_more'),
]
operations = [
migrations.AlterModelOptions(
name='attachment',
options={'verbose_name': 'Attachment', 'verbose_name_plural': 'Attachments'},
),
migrations.AlterModelOptions(
name='glossary',
options={'verbose_name': 'Glossary', 'verbose_name_plural': 'Glossaries'},
),
migrations.RemoveField(
model_name='attachment',
name='course',
),
migrations.RemoveField(
model_name='glossary',
name='course',
),
migrations.RemoveField(
model_name='lesson',
name='course',
),
migrations.RemoveField(
model_name='lesson',
name='is_active',
),
migrations.RemoveField(
model_name='lesson',
name='priority',
),
migrations.AddField(
model_name='attachment',
name='created_at',
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='Created at'),
preserve_default=False,
),
migrations.AddField(
model_name='attachment',
name='updated_at',
field=models.DateTimeField(auto_now=True, verbose_name='Updated At'),
),
migrations.AddField(
model_name='glossary',
name='created_at',
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='Created at'),
preserve_default=False,
),
migrations.AddField(
model_name='glossary',
name='updated_at',
field=models.DateTimeField(auto_now=True, verbose_name='Updated At'),
),
migrations.AlterField(
model_name='lesson',
name='content_type',
field=models.CharField(choices=[('youtube_link', 'Youtube Link'), ('video_file', 'Video File')], max_length=50, verbose_name='Content Type'),
),
migrations.CreateModel(
name='CourseAttachment',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated At')),
('attachment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='course_attachments', to='course.attachment', verbose_name='Attachment')),
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attachments', to='course.course', verbose_name='Course')),
],
options={
'verbose_name': 'Course Attachment',
'verbose_name_plural': 'Course Attachments',
'ordering': ('-id',),
},
),
migrations.CreateModel(
name='CourseGlossary',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated At')),
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='glossaries', to='course.course', verbose_name='Course')),
('glossary', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='course_glossaries', to='course.glossary', verbose_name='Glossary')),
],
options={
'verbose_name': 'Course Glossary',
'verbose_name_plural': 'Course Glossaries',
'ordering': ('-id',),
},
),
migrations.CreateModel(
name='CourseLesson',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(blank=True, max_length=255, null=True, verbose_name='Course Lesson Title')),
('priority', models.IntegerField(blank=True, null=True, verbose_name='Priority')),
('is_active', models.BooleanField(default=True, verbose_name='Is Active')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated At')),
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='lessons', to='course.course', verbose_name='Course')),
('lesson', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='course_lessons', to='course.lesson', verbose_name='Lesson')),
],
),
migrations.AlterUniqueTogether(
name='lessoncompletion',
unique_together=set(),
),
migrations.AddField(
model_name='lessoncompletion',
name='course_lesson',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='completions', to='course.courselesson'),
preserve_default=False,
),
migrations.AlterUniqueTogether(
name='lessoncompletion',
unique_together={('student', 'course_lesson')},
),
migrations.RemoveField(
model_name='lessoncompletion',
name='lesson',
),
]

42
apps/course/migrations/0004_auto_20241122_1913.py

@ -1,42 +0,0 @@
# Generated by Django 3.2.4 on 2024-11-22 19:13
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('course', '0003_participant'),
]
operations = [
migrations.AddField(
model_name='course',
name='created_at',
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='Created at'),
preserve_default=False,
),
migrations.AddField(
model_name='course',
name='updated_at',
field=models.DateTimeField(auto_now=True, verbose_name='Updated At'),
),
migrations.AddField(
model_name='lesson',
name='created_at',
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='Created at'),
preserve_default=False,
),
migrations.AddField(
model_name='lesson',
name='updated_at',
field=models.DateTimeField(auto_now=True, verbose_name='Updated At'),
),
migrations.AddField(
model_name='lessoncompletion',
name='created_at',
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='Created at'),
preserve_default=False,
),
]

2
apps/course/migrations/0005_add_database_indexes.py

@ -7,7 +7,7 @@ class Migration(migrations.Migration):
dependencies = [ dependencies = [
('account', '0003_locationhistory'), ('account', '0003_locationhistory'),
('course', '0004_alter_attachment_options_alter_glossary_options_and_more'),
('course', '0003_alter_course_is_online_alter_course_timing_and_more'),
] ]
operations = [ operations = [

2
apps/course/migrations/0005_participant_unread_messages_count.py

@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('course', '0004_auto_20241122_1913'),
('course', '0003_participant'),
] ]
operations = [ operations = [

82
apps/hadis/management/commands/seed_hadis_transmitter.py

@ -3,37 +3,34 @@ import time
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.db import transaction from django.db import transaction
from django.db.models import Q from django.db.models import Q
# REPLACE 'your_app' with your actual app name
# REPLACE 'your_app' with your actual app name (e.g., apps.hadis.models)
from apps.hadis.models import Hadis, Transmitters, NarratorLayer, HadisTransmitter from apps.hadis.models import Hadis, Transmitters, NarratorLayer, HadisTransmitter
class Command(BaseCommand): class Command(BaseCommand):
help = 'Seeds HadisTransmitter instances with specific constraints'
help = 'Seeds HadisTransmitter instances for ALL Hadis with 5+ transmitters spanning 2-3 layers'
def handle(self, *args, **options): def handle(self, *args, **options):
self.stdout.write("Starting HadisTransmitter seeding...")
self.stdout.write("Starting Global HadisTransmitter seeding...")
# --------------------------------------------------------- # ---------------------------------------------------------
# 1. Fetch the specific Objects
# 1. Fetch ALL Objects
# --------------------------------------------------------- # ---------------------------------------------------------
layers = list(NarratorLayer.objects.filter(id__range=(11, 15)))
transmitters = list(Transmitters.objects.filter(id__range=(84, 91)))
# Hadis query
hadis_qs = Hadis.objects.filter(
Q(id__range=(1800, 1852)) | Q(id__range=(1877, 1889))
)
layers = list(NarratorLayer.objects.all())
transmitters = list(Transmitters.objects.all())
# Fetch all Hadis records
hadis_qs = Hadis.objects.all()
# --------------------------------------------------------- # ---------------------------------------------------------
# 2. Validation # 2. Validation
# --------------------------------------------------------- # ---------------------------------------------------------
if len(layers) < 2:
self.stdout.write(self.style.ERROR(f"Need at least 2 NarratorLayers to satisfy constraints, but found {len(layers)}."))
if len(layers) < 3:
self.stdout.write(self.style.ERROR(f"Need at least 3 NarratorLayers to satisfy constraints, but found {len(layers)}."))
return return
if not transmitters:
self.stdout.write(self.style.ERROR("No Transmitters found in range 84-91."))
if len(transmitters) < 5:
self.stdout.write(self.style.ERROR(f"Need at least 5 Transmitters to satisfy chain length, but found {len(transmitters)}."))
return return
if not hadis_qs.exists(): if not hadis_qs.exists():
self.stdout.write(self.style.ERROR("No Hadis found in the specified ranges."))
self.stdout.write(self.style.ERROR("No Hadis found in the database."))
return return
total_hadis = hadis_qs.count() total_hadis = hadis_qs.count()
@ -42,50 +39,55 @@ class Command(BaseCommand):
# --------------------------------------------------------- # ---------------------------------------------------------
# 3. Creation Loop # 3. Creation Loop
# --------------------------------------------------------- # ---------------------------------------------------------
created_count = 0
created_links_count = 0
self.stdout.write("Beginning processing...") self.stdout.write("Beginning processing...")
for i, hadis in enumerate(hadis_qs, 1): for i, hadis in enumerate(hadis_qs, 1):
# Print progress every 5 items so you know it's not frozen
if i % 5 == 0:
self.stdout.write(f"Processing {i}/{total_hadis} (Hadis ID: {hadis.id})...")
# Progress indicator
if i % 100 == 0:
self.stdout.write(f"Processing {i}/{total_hadis}...")
# Wrap PER ITEM in transaction to avoid long db locks
with transaction.atomic(): with transaction.atomic():
# CONSTRAINT 1: Each hadis must have 3-4 transmitters
chain_length = random.randint(3, 4)
# Clean existing transmitters for this hadis to avoid duplicates/conflicts if re-running
# Remove this line if you want to APPEND to existing data instead of resetting
HadisTransmitter.objects.filter(hadis=hadis).delete()
# CONSTRAINT 1: Chain length must be at least 5 (let's do 5 to 7)
chain_length = random.randint(5, 7)
# CONSTRAINT 2: Must have at least 2-3 narrator layers
target_unique_layers = random.randint(2, 3)
if len(transmitters) < chain_length:
self.stdout.write(self.style.WARNING(f"Not enough transmitters. Skipping Hadis {hadis.id}."))
continue
# --- Logic to Select Transmitters and Layers ---
# Pick unique transmitters
# A. Select Transmitters
selected_transmitters = random.sample(transmitters, chain_length) selected_transmitters = random.sample(transmitters, chain_length)
# CONSTRAINT 2: Transmitters must be separated to at least 2 narrator layers
# LOGIC FIX: Instead of a while loop, we force the condition explicitly.
# B. Select Layers
# First, pick the 'mandatory' unique layers to satisfy the constraint
mandatory_layers = random.sample(layers, target_unique_layers)
# Step A: Pick 2 DISTINCT layers guaranteed
guaranteed_layers = random.sample(layers, 2)
# Second, fill the remaining slots in the chain
remaining_slots = chain_length - target_unique_layers
# Step B: Fill the remaining slots (1 or 2 slots) with random layers
remaining_slots = chain_length - 2
# We can pick from ANY layer for the remaining slots (including the mandatory ones)
other_layers = [random.choice(layers) for _ in range(remaining_slots)] other_layers = [random.choice(layers) for _ in range(remaining_slots)]
# Step C: Combine and Shuffle so the distinct ones aren't always first
final_layers = guaranteed_layers + other_layers
random.shuffle(final_layers)
# Combine and Shuffle
final_layers_pool = mandatory_layers + other_layers
random.shuffle(final_layers_pool)
# Create the connections
# --- Create Connections ---
for index, transmitter in enumerate(selected_transmitters): for index, transmitter in enumerate(selected_transmitters):
HadisTransmitter.objects.create( HadisTransmitter.objects.create(
hadis=hadis, hadis=hadis,
transmitter=transmitter, transmitter=transmitter,
narrator_layer=final_layers[index],
narrator_layer=final_layers_pool[index],
order=index, order=index,
# Check if transmitter has 'reliability' (ForeignKey) or if it's a direct field
status=transmitter.reliability if hasattr(transmitter, 'reliability') else None status=transmitter.reliability if hasattr(transmitter, 'reliability') else None
) )
created_count += 1
created_links_count += 1
self.stdout.write(self.style.SUCCESS(f"Done! Successfully created {created_count} HadisTransmitter instances."))
self.stdout.write(self.style.SUCCESS(f"Done! Created {created_links_count} HadisTransmitter connections for {total_hadis} Hadiths."))

218
apps/hadis/management/commands/seed_transmitters.py

@ -1,109 +1,133 @@
import random import random
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.db import transaction from django.db import transaction
# REPLACE 'apps.hadis.models' WITH YOUR ACTUAL APP PATH
from apps.hadis.models import Transmitters, TransmitterOpinion, TransmitterOriginalText, OpinionStatus
# REPLACE 'apps.hadis.models' with your actual app path if different
from apps.hadis.models import Transmitters, TransmitterReliability
class Command(BaseCommand): class Command(BaseCommand):
help = 'Seeds TransmitterOpinion and TransmitterOriginalText for transmitters 84-91'
help = 'Seeds database with 50 famous Islamic transmitters and scholars'
def create_json_field(self, en_text, fa_text, ru_text):
"""Helper to create the standard JSON structure"""
return [
{"text": en_text, "language_code": "en"},
{"text": fa_text, "language_code": "fa"},
{"text": ru_text, "language_code": "ru"}
]
def handle(self, *args, **options): def handle(self, *args, **options):
self.stdout.write("Starting Transmitter Details seeding...")
# ---------------------------------------------------------
# 1. Fetch Target Objects
# ---------------------------------------------------------
transmitters = Transmitters.objects.filter(id__range=(84, 91))
if not transmitters.exists():
self.stdout.write(self.style.ERROR("No Transmitters found in range 84-91."))
return
self.stdout.write("Starting to seed transmitters...")
# Fetch OpinionStatus objects
# We need these to populate the 'status' ForeignKey in TransmitterOpinion
statuses = list(OpinionStatus.objects.all())
# 1. Fetch available reliability IDs (7-17)
# We assume these exist based on your prompt.
reliability_ids = list(range(7, 18))
# Fallback: If no statuses exist, we can't create opinions safely without knowing your Status model fields.
if not statuses:
self.stdout.write(self.style.ERROR("No 'OpinionStatus' objects found! Please create some via Admin first."))
return
self.stdout.write(f"Found {transmitters.count()} Transmitters and {len(statuses)} Opinion Statuses.")
# ---------------------------------------------------------
# 2. Data Generators (Helpers)
# ---------------------------------------------------------
scholars = [
{"en": "Al-Dhahabi", "ar": "الذهبي", "fa": "ذهبی"},
{"en": "Ibn Hajar", "ar": "ابن حجر", "fa": "ابن حجر"},
{"en": "Al-Tusi", "ar": "الطوسي", "fa": "طوسی"},
{"en": "Al-Najashi", "ar": "النجاشي", "fa": "نجاشی"},
]
opinion_texts = [
{"en": "He is trustworthy and reliable.", "ar": "هو ثقة ثبت.", "fa": "او ثقه و مورد اعتماد است."},
{"en": "His memory was weak in later years.", "ar": "كان سيء الحفظ في آخره.", "fa": "حافظه او در اواخر عمر ضعیف بود."},
{"en": "Unknown status.", "ar": "مجهول الحال.", "fa": "مجهول است."},
{"en": "Highly praised by scholars.", "ar": "ممدوح عند العلماء.", "fa": "مورد ستایش علما است."},
]
book_titles = [
{"en": "Book of Traditions", "ar": "كتاب الحديث", "fa": "کتاب حدیث"},
{"en": "Treatise on Rights", "ar": "رسالة الحقوق", "fa": "رساله حقوق"},
{"en": "The Clarification", "ar": "التبين", "fa": "تبیین"},
{"en": "Collection of Virtues", "ar": "مجموع الفضائل", "fa": "مجموعه فضائل"},
# Verify reliabilities exist, or create a fallback
existing_reliabilities = list(TransmitterReliability.objects.filter(id__in=reliability_ids))
if not existing_reliabilities:
self.stdout.write(self.style.WARNING("No TransmitterReliability found in range 7-17. Creating a default one..."))
default_rel = TransmitterReliability.objects.create(
id=7,
title=self.create_json_field("Trustworthy", "ثقه", "Надежный"),
color='green'
)
existing_reliabilities = [default_rel]
# 2. Data Definition (List of 50)
# Structure: (EN Name, FA Name, RU Name, Death Year, Origin EN, Origin FA, Origin RU)
data_source = [
("Abu Hurairah", "ابو هریره", "Абу Хурайра", 59, "Yemen", "یمن", "Йемен"),
("Anas ibn Malik", "انس بن مالک", "Анас ибн Малик", 93, "Medina", "مدینه", "Медина"),
("Aisha bint Abi Bakr", "عایشه بنت ابی‌بکر", "Аиша бинт Абу Бакр", 58, "Mecca", "مکه", "Мекка"),
("Abdullah ibn Umar", "عبدالله بن عمر", "Абдуллах ибн Умар", 73, "Mecca", "مکه", "Мекка"),
("Abdullah ibn Abbas", "عبدالله بن عباس", "Абдуллах ибн Аббас", 68, "Mecca", "مکه", "Мекка"),
("Jabir ibn Abdullah", "جابر بن عبدالله", "Джабир ибн Абдуллах", 78, "Medina", "مدینه", "Медина"),
("Abu Sa'id al-Khudri", "ابو سعید خدری", "Абу Саид аль-Худри", 74, "Medina", "مدینه", "Медина"),
("Abdullah ibn Mas'ud", "عبدالله بن مسعود", "Абдуллах ибн Масуд", 32, "Mecca", "مکه", "Мекка"),
("Ali ibn Abi Talib", "علی بن ابی‌طالب", "Али ибн Абу Талиб", 40, "Mecca", "مکه", "Мекка"),
("Umar ibn al-Khattab", "عمر بن خطاب", "Умар ибн аль-Хаттаб", 23, "Mecca", "مکه", "Мекка"),
("Abu Bakr as-Siddiq", "ابوبکر صدیق", "Абу Бакр ас-Сиддик", 13, "Mecca", "مکه", "Мекка"),
("Uthman ibn Affan", "عثمان بن عفان", "Усман ибн Аффан", 35, "Mecca", "مکه", "Мекка"),
("Salman al-Farsi", "سلمان فارسی", "Салман аль-Фариси", 36, "Isfahan", "اصفهان", "Исфахан"),
("Bilal ibn Rabah", "بلال حبشی", "Билал ибн Рабах", 20, "Mecca", "مکه", "Мекка"),
("Ammar ibn Yasir", "عمار یاسر", "Аммар ибн Ясир", 37, "Mecca", "مکه", "Мекка"),
("Abu Dharr al-Ghifari", "ابوذر غفاری", "Абу Зарр аль-Гифари", 32, "Ghifar", "غفار", "Гифар"),
("Miqdad ibn Aswad", "مقداد بن اسود", "Микдад ибн Асвад", 33, "Mecca", "مکه", "Мекка"),
("Talhah ibn Ubaydullah", "طلحه بن عبیدالله", "Талха ибн Убайдуллах", 36, "Mecca", "مکه", "Мекка"),
("Zubayr ibn al-Awam", "زبیر بن عوام", "Зубайр ибн аль-Аввам", 36, "Mecca", "مکه", "Мекка"),
("Sa'd ibn Abi Waqqas", "سعد بن ابی‌وقاص", "Саад ибн Абу Ваккас", 55, "Mecca", "مکه", "Мекка"),
("Saeed ibn al-Musayyib", "سعید بن مسیب", "Саид ибн аль-Мусаййиб", 94, "Medina", "مدینه", "Медина"),
("Urwah ibn al-Zubayr", "عروه بن زبیر", "Урва ибн аз-Зубайр", 94, "Medina", "مدینه", "Медина"),
("Al-Hasan al-Basri", "حسن بصری", "Аль-Хасан аль-Басри", 110, "Medina", "مدینه", "Медина"),
("Muhammad ibn Sirin", "محمد بن سیرین", "Мухаммад ибн Сирин", 110, "Basra", "بصره", "Басра"),
("Ibn Shihab al-Zuhri", "ابن شهاب زهری", "Ибн Шихаб аз-Зухри", 124, "Medina", "مدینه", "Медина"),
("Nafi Mawla Ibn Umar", "نافع مولی ابن عمر", "Нафи мавля Ибн Умар", 117, "Medina", "مدینه", "Медина"),
("Malik ibn Anas", "مالک بن انس", "Малик ибн Анас", 179, "Medina", "مدینه", "Медина"),
("Al-Shafi'i", "محمد بن ادریس شافعی", "Аш-Шафии", 204, "Gaza", "غزه", "Газа"),
("Ahmad ibn Hanbal", "احمد بن حنبل", "Ахмад ибн Ханбаль", 241, "Baghdad", "بغداد", "Багдад"),
("Sufyan al-Thawri", "سفیان ثوری", "Суфьян ас-Саури", 161, "Kufa", "کوفه", "Куфа"),
("Sufyan ibn Uyaynah", "سفیان بن عیینه", "Суфьян ибн Уйайна", 198, "Kufa", "کوفه", "Куфа"),
("Abdullah ibn al-Mubarak", "عبدالله بن مبارک", "Абдуллах ибн аль-Мубарак", 181, "Merv", "مرو", "Мерв"),
("Waki ibn al-Jarrah", "وکیع بن جراح", "Ваки ибн аль-Джаррах", 197, "Kufa", "کوفه", "Куфа"),
("Shu'bah ibn al-Hajjaj", "شعبه بن حجاج", "Шуба ибн аль-Хаджадж", 160, "Wasit", "واسط", "Васит"),
("Yahya ibn Ma'in", "یحیی بن معین", "Яхья ибн Маин", 233, "Baghdad", "بغداد", "Багдад"),
("Ali ibn al-Madini", "علی بن مدینی", "Али ибн аль-Мадини", 234, "Basra", "بصره", "Басра"),
("Muhammad al-Bukhari", "محمد بخاری", "Мухаммад аль-Бухари", 256, "Bukhara", "بخارا", "Бухара"),
("Muslim ibn al-Hajjaj", "مسلم نیشابوری", "Муслим ибн аль-Хаджадж", 261, "Nishapur", "نیشابور", "Нишапур"),
("Abu Dawood", "ابوداوود سجستانی", "Абу Дауд", 275, "Sistan", "سیستان", "Систан"),
("Al-Tirmidhi", "ترمذی", "Ат-Тирмизи", 279, "Termez", "ترمز", "Термез"),
("Al-Nasa'i", "نسائی", "Ан-Насаи", 303, "Nasa", "نسا", "Наса"),
("Ibn Majah", "ابن ماجه", "Ибн Маджа", 273, "Qazvin", "قزوین", "Казвин"),
("Al-Daraqutni", "دارقطنی", "Ад-Даракутни", 385, "Baghdad", "بغداد", "Багдад"),
("Al-Bayhaqi", "بیهقی", "Аль-Байхаки", 458, "Bayhaq", "بیهق", "Байхак"),
("Al-Hakim al-Nishapuri", "حاکم نیشابوری", "Аль-Хаким ан-Нишапури", 405, "Nishapur", "نیشابور", "Нишапур"),
("Al-Nawawi", "نووی", "Ан-Навави", 676, "Nawa", "نوا", "Нава"),
("Al-Dhahabi", "ذهبی", "Аз-Захаби", 748, "Damascus", "دمشق", "Дамаск"),
("Ibn Hajar al-Asqalani", "ابن حجر عسقلانی", "Ибн Хаджар аль-Аскаляни", 852, "Cairo", "قاهره", "Каир"),
("Ibn Kathir", "ابن کثیر", "Ибн Касир", 774, "Damascus", "دمشق", "Дамаск"),
("Al-Tabari", "طبری", "Ат-Табари", 310, "Amol", "آمل", "Амоль"),
] ]
def make_json_field(data_dict):
"""Converts simple dict {'en': 'X', 'fa': 'Y'} to your model's JSON structure"""
return [
{"language_code": "en", "text": data_dict.get("en", "")},
{"language_code": "ar", "text": data_dict.get("ar", "")},
{"language_code": "fa", "text": data_dict.get("fa", "")},
]
# ---------------------------------------------------------
# 3. Creation Loop
# ---------------------------------------------------------
counts = {'opinions': 0, 'texts': 0}
# 3. Execution Loop
created_count = 0
with transaction.atomic(): with transaction.atomic():
for t in transmitters:
self.stdout.write(f"Processing {t.full_name[0]['text'] if t.full_name else t.id}...")
# --- A. Create TransmitterOpinion (1 to 2 per person) ---
for _ in range(random.randint(1, 2)):
scholar = random.choice(scholars)
text = random.choice(opinion_texts)
status = random.choice(statuses)
TransmitterOpinion.objects.create(
transmitter=t,
scholar_name=make_json_field(scholar),
opinion_text=make_json_field(text),
status=status
)
counts['opinions'] += 1
# --- B. Create TransmitterOriginalText (1 to 2 per person) ---
for _ in range(random.randint(1, 2)):
title = random.choice(book_titles)
# Simple dummy text
body = {
"en": f"This is an excerpt from {title['en']}...",
"ar": f"هذا مقتطف من {title['ar']}...",
"fa": f"این بخشی از {title['fa']} است..."
}
TransmitterOriginalText.objects.create(
transmitter=t,
title=make_json_field(title),
text=make_json_field(body),
translation=make_json_field(body), # Using same text for translation as placeholder
# Note: 'slug' and 'share_link' are handled by your model's save() method automatically
)
counts['texts'] += 1
self.stdout.write(self.style.SUCCESS(
f"Done! Created {counts['opinions']} Opinions and {counts['texts']} Original Texts."
))
for entry in data_source:
en_name, fa_name, ru_name, death_year, en_origin, fa_origin, ru_origin = entry
# Check if exists (by English Name) to allow re-running script
if Transmitters.objects.filter(full_name__contains=[{"text": en_name, "language_code": "en"}]).exists():
self.stdout.write(f"Skipping {en_name} (already exists)")
continue
# Prepare JSON fields
full_name_json = self.create_json_field(en_name, fa_name, ru_name)
origin_json = self.create_json_field(en_origin, fa_origin, ru_origin)
# Simple defaults for other text fields
desc_json = self.create_json_field(
f"A renowned scholar/narrator from {en_origin}",
f"از راویان/علمای مشهور اهل {fa_origin}",
f"Известный передатчик/ученый из {ru_origin}"
)
# Randomly pick reliability
reliability = random.choice(existing_reliabilities)
# Create Object
Transmitters.objects.create(
full_name=full_name_json,
origin=origin_json,
lived_in=origin_json, # Assume lived where born for simplicity
died_in=self.create_json_field("Unknown", "نامشخص", "Неизвестно"),
death_year_hijri=death_year,
description=desc_json,
reliability=reliability,
# Setting defaults for required JSON fields
kunya=self.create_json_field("", "", ""),
known_as=self.create_json_field("", "", ""),
nickname=self.create_json_field("", "", ""),
madhhab='unknown', # Default as per your choices
)
created_count += 1
self.stdout.write(self.style.SUCCESS(f"Successfully created {created_count} new Transmitters!"))

4
apps/hadis/models/hadis.py

@ -192,8 +192,8 @@ class Hadis(models.Model):
share_link = models.CharField(max_length=255, verbose_name=_('share link'), null=True, blank=True) share_link = models.CharField(max_length=255, verbose_name=_('share link'), null=True, blank=True)
explanation = models.JSONField(default = list , verbose_name=_('Explanation')) 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'))
# 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')) created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'))
updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at')) updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at'))

8
apps/hadis/models/transmitter.py

@ -162,10 +162,10 @@ class Transmitters(models.Model):
class MadhhabChoices(models.TextChoices): class MadhhabChoices(models.TextChoices):
SHIA = 'shia', _('Shia') SHIA = 'shia', _('Shia')
SUNNI = 'sunni', _('Sunni') SUNNI = 'sunni', _('Sunni')
HANAFI = 'hanafi', _('Hanafi')
MALIKI = 'maliki', _('Maliki')
SHAFII = 'shafii', _('Shafi\'i')
HANBALI = 'hanbali', _('Hanbali')
# HANAFI = 'hanafi', _('Hanafi')
# MALIKI = 'maliki', _('Maliki')
# SHAFII = 'shafii', _('Shafi\'i')
# HANBALI = 'hanbali', _('Hanbali')
OTHER = 'other', _('Other') OTHER = 'other', _('Other')
UNKNOWN = 'unknown', _('Unknown') UNKNOWN = 'unknown', _('Unknown')

44
apps/hadis/serializers/hadis.py

@ -618,30 +618,30 @@ class HadisBasicSerializer(serializers.ModelSerializer):
title = LocalizedField() title = LocalizedField()
title_narrator = LocalizedField() title_narrator = LocalizedField()
explanation = LocalizedField() explanation = LocalizedField()
explanations = serializers.SerializerMethodField()
# explanations = serializers.SerializerMethodField()
class Meta: class Meta:
model = Hadis model = Hadis
fields = [ fields = [
'id', 'slug', 'title','bookmark', 'title_narrator', 'text', 'id', 'slug', 'title','bookmark', 'title_narrator', 'text',
'translation', 'share_link','explanation', 'explanations','category'
'translation', 'share_link','explanation','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'
# 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', '')
})
# 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
# return explanations_list if explanations_list else None
def get_category(self, obj): def get_category(self, obj):
@ -694,20 +694,20 @@ class HadisDetailSerializer(serializers.ModelSerializer):
) )
reference_images = SerializerMethodField() reference_images = SerializerMethodField()
address = LocalizedField() address = LocalizedField()
address_details = serializers.SerializerMethodField()
# address_details = serializers.SerializerMethodField()
class Meta: class Meta:
model = Hadis model = Hadis
fields = [ fields = [
'id', 'number', 'slug','hadis_status', 'links','share_link', 'id', 'number', 'slug','hadis_status', 'links','share_link',
'tags','references','reference_images','address', 'address_details'
'tags','references','reference_images','address'
] ]
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_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): def get_reference_images(self, obj):
"""Get all reference images from all references""" """Get all reference images from all references"""

3
entrypoint.sh

@ -6,9 +6,10 @@ python manage.py migrate
python manage.py collectstatic --noinput python manage.py collectstatic --noinput
# Seed Russian data (only runs once, skips if data exists) # Seed Russian data (only runs once, skips if data exists)
python manage.py seed_hadis_transmitter
# python manage.py seed_russian_data # python manage.py seed_russian_data
# python manage.py hadisreferences # python manage.py hadisreferences
python manage.py seed_complete_hadis_data
# python manage.py seed_complete_hadis_data
# python manage.py populate_books # python manage.py populate_books
# python manage.py populate_book_reference # python manage.py populate_book_reference
# python manage.py populate_refrence_images # python manage.py populate_refrence_images

Loading…
Cancel
Save