Browse Source
Add Russian data seeding command and update entrypoint script
Add Russian data seeding command and update entrypoint script
- Introduced a new management command to seed Russian language data for Hadis, HadisCategory, and HadisSect. - Updated entrypoint script to include the new command for seeding Russian data during initialization.master
2 changed files with 349 additions and 0 deletions
@ -0,0 +1,346 @@ |
|||
import random |
|||
import uuid |
|||
from django.core.management.base import BaseCommand |
|||
from django.db import transaction |
|||
from apps.hadis.models import Hadis, HadisCategory, HadisSect |
|||
|
|||
|
|||
# Russian word patterns for random combination |
|||
RUSSIAN_CATEGORY_PREFIXES = [ |
|||
"Основы", "Принципы", "Учение", "Заповеди", "Наставления", |
|||
"Мудрость", "Знания", "Истина", "Путь", "Свет", |
|||
"Благочестие", "Праведность", "Духовность", "Вера", "Надежда", |
|||
] |
|||
|
|||
RUSSIAN_CATEGORY_TOPICS = [ |
|||
"молитвы", "поста", "милостыни", "паломничества", "джихада", |
|||
"брака", "семьи", "торговли", "справедливости", "терпения", |
|||
"благодарности", "покаяния", "прощения", "любви", "мира", |
|||
"знания", "мудрости", "веры", "надежды", "смирения", |
|||
] |
|||
|
|||
RUSSIAN_CATEGORY_SUFFIXES = [ |
|||
"в исламе", "для верующих", "и праведность", "и благочестие", |
|||
"и духовность", "и истина", "и свет", "и путь", |
|||
] |
|||
|
|||
RUSSIAN_HADIS_OPENINGS = [ |
|||
"Пророк (мир ему) сказал:", |
|||
"Имам Али (мир ему) сказал:", |
|||
"Имам Садик (мир ему) сказал:", |
|||
"Имам Хусейн (мир ему) сказал:", |
|||
"Передается от Пророка (мир ему):", |
|||
"Рассказывает имам Бакир (мир ему):", |
|||
"Сообщается от имама Казима (мир ему):", |
|||
] |
|||
|
|||
RUSSIAN_HADIS_BODIES = [ |
|||
"Лучший из вас тот, кто учится и учит других.", |
|||
"Ищите знания от колыбели до могилы.", |
|||
"Терпение - ключ к облегчению.", |
|||
"Молитва - столп религии.", |
|||
"Знание - свет для сердца.", |
|||
"Доброта к родителям - обязанность верующего.", |
|||
"Справедливость - основа власти.", |
|||
"Правда ведет к благочестию.", |
|||
"Смирение возвышает человека.", |
|||
"Благодарность увеличивает благословения.", |
|||
"Прощение - признак силы.", |
|||
"Терпение приносит награду.", |
|||
"Вера укрепляется добрыми делами.", |
|||
"Знание без действия бесполезно.", |
|||
"Лучшее богатство - довольство.", |
|||
"Самый сильный - тот, кто владеет собой в гневе.", |
|||
"Сосед имеет права на тебя.", |
|||
"Улыбка - это милостыня.", |
|||
"Чистота - половина веры.", |
|||
"Намерение определяет ценность дела.", |
|||
] |
|||
|
|||
RUSSIAN_HADIS_ENDINGS = [ |
|||
"И это истина от Всевышнего.", |
|||
"Так учит нас ислам.", |
|||
"Это путь праведных.", |
|||
"Запомните это наставление.", |
|||
"Следуйте этому пути.", |
|||
"Это мудрость пророков.", |
|||
"Берегите это знание.", |
|||
"", |
|||
] |
|||
|
|||
RUSSIAN_SECT_DATA = { |
|||
'shia': { |
|||
'title': 'Шиизм', |
|||
'description': 'Шиитское направление ислама, следующее за семьей Пророка (мир ему и его семье).', |
|||
}, |
|||
'sunni': { |
|||
'title': 'Суннизм', |
|||
'description': 'Суннитское направление ислама, следующее сунне Пророка (мир ему).', |
|||
}, |
|||
} |
|||
|
|||
|
|||
def make_json_field(text, lang='ru'): |
|||
"""Create JSON field in the format used by the models.""" |
|||
return [{'text': text, 'language_code': lang}] |
|||
|
|||
|
|||
def generate_unique_slug(prefix, number): |
|||
"""Generate a unique slug with prefix and number.""" |
|||
unique_suffix = uuid.uuid4().hex[:8] |
|||
return f"{prefix}-{number}-{unique_suffix}" |
|||
|
|||
|
|||
def generate_category_title(): |
|||
"""Generate a random Russian category title.""" |
|||
prefix = random.choice(RUSSIAN_CATEGORY_PREFIXES) |
|||
topic = random.choice(RUSSIAN_CATEGORY_TOPICS) |
|||
suffix = random.choice(RUSSIAN_CATEGORY_SUFFIXES) if random.random() > 0.5 else "" |
|||
return f"{prefix} {topic} {suffix}".strip() |
|||
|
|||
|
|||
def generate_category_description(title): |
|||
"""Generate a description based on the title.""" |
|||
descriptions = [ |
|||
f"Раздел посвящен теме: {title}. Здесь собраны важные хадисы и наставления.", |
|||
f"В этом разделе вы найдете хадисы о {title.lower()}.", |
|||
f"Категория содержит материалы по теме: {title}.", |
|||
f"Изучайте {title.lower()} через достоверные хадисы.", |
|||
] |
|||
return random.choice(descriptions) |
|||
|
|||
|
|||
def generate_hadis_text(): |
|||
"""Generate a random hadis text in Russian.""" |
|||
opening = random.choice(RUSSIAN_HADIS_OPENINGS) |
|||
body = random.choice(RUSSIAN_HADIS_BODIES) |
|||
ending = random.choice(RUSSIAN_HADIS_ENDINGS) |
|||
return f"{opening} {body} {ending}".strip() |
|||
|
|||
|
|||
def generate_hadis_title(): |
|||
"""Generate a random hadis title.""" |
|||
topics = [ |
|||
"О терпении и награде", |
|||
"О знании и мудрости", |
|||
"О молитве и поклонении", |
|||
"О справедливости и праведности", |
|||
"О семье и воспитании", |
|||
"О доброте и милосердии", |
|||
"О вере и благочестии", |
|||
"О покаянии и прощении", |
|||
"О благодарности Аллаху", |
|||
"О смирении и скромности", |
|||
"О правде и честности", |
|||
"О соседях и обществе", |
|||
"О торговле и справедливости", |
|||
"О чистоте и гигиене", |
|||
"О намерении и искренности", |
|||
] |
|||
return random.choice(topics) |
|||
|
|||
|
|||
class Command(BaseCommand): |
|||
help = 'Seed Russian language data for HadisSect, HadisCategory (3 levels), and Hadis (up to 500 records)' |
|||
|
|||
# Configuration constants |
|||
MAX_HADIS_RECORDS = 500 |
|||
HADIS_PER_CATEGORY = 10 |
|||
|
|||
def add_arguments(self, parser): |
|||
parser.add_argument( |
|||
'--clear', |
|||
action='store_true', |
|||
help='Clear existing data before seeding', |
|||
) |
|||
parser.add_argument( |
|||
'--force', |
|||
action='store_true', |
|||
help='Force seeding even if data already exists', |
|||
) |
|||
|
|||
def handle(self, *args, **options): |
|||
self.stdout.write(self.style.WARNING('=== Starting Russian Data Seeding ===')) |
|||
|
|||
# Check if data already exists (prevent re-running in loops) |
|||
existing_hadis = Hadis.objects.count() |
|||
existing_categories = HadisCategory.objects.count() |
|||
|
|||
if existing_hadis >= self.MAX_HADIS_RECORDS and not options['force'] and not options['clear']: |
|||
self.stdout.write(self.style.SUCCESS( |
|||
f'Data already seeded ({existing_hadis} hadis, {existing_categories} categories). ' |
|||
'Use --force to override or --clear to reset.' |
|||
)) |
|||
return |
|||
|
|||
if options['clear']: |
|||
self.stdout.write(self.style.WARNING('Clearing existing data...')) |
|||
Hadis.objects.all().delete() |
|||
HadisCategory.objects.all().delete() |
|||
HadisSect.objects.all().delete() |
|||
self.stdout.write(self.style.SUCCESS('Existing data cleared.')) |
|||
|
|||
try: |
|||
with transaction.atomic(): |
|||
# Step 1: Create Sects |
|||
sects = self.create_sects() |
|||
|
|||
# Step 2: Create Categories (3 levels) |
|||
categories = self.create_categories(sects) |
|||
|
|||
# Step 3: Create Hadis (up to 500 records, distributed across categories) |
|||
self.create_hadis(categories) |
|||
|
|||
self.print_statistics() |
|||
self.stdout.write(self.style.SUCCESS('=== Russian Data Seeding Complete ===')) |
|||
|
|||
except Exception as e: |
|||
self.stdout.write(self.style.ERROR(f'Error during seeding: {str(e)}')) |
|||
raise |
|||
|
|||
def create_sects(self): |
|||
"""Create or update HadisSect entries.""" |
|||
self.stdout.write('Creating sects...') |
|||
sects = {} |
|||
|
|||
for sect_type, data in RUSSIAN_SECT_DATA.items(): |
|||
sect, created = HadisSect.objects.update_or_create( |
|||
sect_type=sect_type, |
|||
defaults={ |
|||
'title': make_json_field(data['title']), |
|||
'description': make_json_field(data['description']), |
|||
'is_active': True, |
|||
'order': 1 if sect_type == 'shia' else 2, |
|||
} |
|||
) |
|||
sects[sect_type] = sect |
|||
status = 'Created' if created else 'Updated' |
|||
self.stdout.write(f" {status} sect: {data['title']}") |
|||
|
|||
return sects |
|||
|
|||
def create_categories(self, sects): |
|||
"""Create 3-level category tree for each sect and source type.""" |
|||
self.stdout.write('Creating category tree (3 levels)...') |
|||
all_leaf_categories = [] |
|||
|
|||
# Limit source types to control total number of categories |
|||
source_types = ['hadith', 'quran'] |
|||
|
|||
for sect_type, sect in sects.items(): |
|||
for source_type in source_types: |
|||
self.stdout.write(f" Creating categories for {sect_type}/{source_type}...") |
|||
|
|||
# Level 1: Root categories (2 per source type to limit total) |
|||
for i in range(2): |
|||
level1_title = generate_category_title() |
|||
level1_cat = HadisCategory.objects.create( |
|||
parent=None, |
|||
sect=sect, |
|||
source_type=source_type, |
|||
title=make_json_field(level1_title), |
|||
description=make_json_field(generate_category_description(level1_title)), |
|||
order=i + 1, |
|||
) |
|||
|
|||
# Level 2: Child categories (2 per level 1) |
|||
for j in range(2): |
|||
level2_title = generate_category_title() |
|||
level2_cat = HadisCategory.objects.create( |
|||
parent=level1_cat, |
|||
sect=sect, |
|||
source_type=source_type, |
|||
title=make_json_field(level2_title), |
|||
description=make_json_field(generate_category_description(level2_title)), |
|||
order=j + 1, |
|||
) |
|||
|
|||
# Level 3: Leaf categories (2-3 per level 2) |
|||
num_level3 = random.randint(2, 3) |
|||
for k in range(num_level3): |
|||
level3_title = generate_category_title() |
|||
level3_cat = HadisCategory.objects.create( |
|||
parent=level2_cat, |
|||
sect=sect, |
|||
source_type=source_type, |
|||
title=make_json_field(level3_title), |
|||
description=make_json_field(generate_category_description(level3_title)), |
|||
order=k + 1, |
|||
) |
|||
all_leaf_categories.append(level3_cat) |
|||
|
|||
total_categories = HadisCategory.objects.count() |
|||
self.stdout.write(self.style.SUCCESS(f" Created {total_categories} categories total")) |
|||
self.stdout.write(self.style.SUCCESS(f" Leaf categories: {len(all_leaf_categories)}")) |
|||
|
|||
return all_leaf_categories |
|||
|
|||
def create_hadis(self, leaf_categories): |
|||
"""Create hadis records distributed across categories, up to MAX_HADIS_RECORDS.""" |
|||
self.stdout.write(f'Creating hadis entries (max {self.MAX_HADIS_RECORDS})...') |
|||
hadis_count = 0 |
|||
hadis_number = 1 |
|||
|
|||
# Calculate hadis per category to reach ~500 total |
|||
num_categories = len(leaf_categories) |
|||
if num_categories == 0: |
|||
self.stdout.write(self.style.WARNING('No leaf categories found!')) |
|||
return |
|||
|
|||
hadis_per_cat = max(self.HADIS_PER_CATEGORY, self.MAX_HADIS_RECORDS // num_categories) |
|||
|
|||
for idx, category in enumerate(leaf_categories): |
|||
# Stop if we've reached the limit |
|||
if hadis_count >= self.MAX_HADIS_RECORDS: |
|||
break |
|||
|
|||
# Create hadis for this category |
|||
for i in range(hadis_per_cat): |
|||
if hadis_count >= self.MAX_HADIS_RECORDS: |
|||
break |
|||
|
|||
title = generate_hadis_title() |
|||
text = generate_hadis_text() |
|||
translation = text # Same as text since it's already in Russian |
|||
|
|||
# Generate unique slug to avoid duplicates |
|||
slug = generate_unique_slug('hadis-ru', hadis_number) |
|||
|
|||
Hadis.objects.create( |
|||
category=category, |
|||
number=hadis_number, |
|||
slug=slug, |
|||
title=make_json_field(title), |
|||
title_narrator=make_json_field(random.choice(RUSSIAN_HADIS_OPENINGS).rstrip(':')), |
|||
description=make_json_field(f"Хадис номер {hadis_number} из категории {category.title[0]['text']}"), |
|||
text=text, |
|||
translation=make_json_field(translation), |
|||
status=True, |
|||
address=make_json_field(f"Том {random.randint(1, 10)}, страница {random.randint(1, 500)}"), |
|||
explanation=make_json_field(f"Этот хадис учит нас важности {title.lower()}."), |
|||
) |
|||
hadis_number += 1 |
|||
hadis_count += 1 |
|||
|
|||
# Progress indicator every 5 categories |
|||
if idx % 5 == 0: |
|||
self.stdout.write(f" Progress: {hadis_count}/{self.MAX_HADIS_RECORDS} hadis created...") |
|||
|
|||
self.stdout.write(self.style.SUCCESS(f" Created {hadis_count} hadis entries")) |
|||
|
|||
def print_statistics(self): |
|||
"""Print final statistics.""" |
|||
self.stdout.write("\n=== Statistics ===") |
|||
self.stdout.write(f"Sects: {HadisSect.objects.count()}") |
|||
self.stdout.write(f"Categories: {HadisCategory.objects.count()}") |
|||
self.stdout.write(f"Hadis: {Hadis.objects.count()}") |
|||
|
|||
# Show hadis per category stats |
|||
leaf_cats = [] |
|||
for cat in HadisCategory.objects.all(): |
|||
if not HadisCategory.objects.filter(parent=cat).exists(): |
|||
leaf_cats.append(cat) |
|||
|
|||
if leaf_cats: |
|||
hadis_counts = [Hadis.objects.filter(category=cat).count() for cat in leaf_cats] |
|||
self.stdout.write(f"Hadis per leaf category: min={min(hadis_counts)}, max={max(hadis_counts)}, avg={sum(hadis_counts)/len(hadis_counts):.1f}") |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue