You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
346 lines
15 KiB
346 lines
15 KiB
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}")
|