""" 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: # Phase 0: Fix existing data integrity issues BEFORE starting transaction self.stdout.write('Phase 0: Fixing existing data integrity issues...') self.fix_existing_data() 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 fix_existing_data(self): """Fix all existing data integrity issues before starting main transaction""" from django.utils.text import slugify from django.db.models import Count, Q from django.db import connection self.stdout.write('=' * 60) self.stdout.write('PHASE 0: FIXING EXISTING DATA INTEGRITY ISSUES') self.stdout.write('=' * 60) # Use raw SQL to find ALL records with empty slugs - more reliable with connection.cursor() as cursor: cursor.execute(""" SELECT id, number FROM hadis_narratorlayer WHERE slug IS NULL OR slug = '' OR TRIM(slug) = '' """) empty_slug_rows = cursor.fetchall() self.stdout.write(f'Found {len(empty_slug_rows)} NarratorLayer records with empty slugs (via raw SQL)') # Fix each one fixed_count = 0 for row_id, row_number in empty_slug_rows: try: layer = NarratorLayer.objects.get(pk=row_id) # Generate slug try: if layer.name and isinstance(layer.name, list) and len(layer.name) > 0: text = layer.name[0].get('text', '').strip() if text: new_slug = slugify(text) else: new_slug = f"layer-{layer.number}" else: new_slug = f"layer-{layer.number}" except (IndexError, KeyError, AttributeError, TypeError): new_slug = f"layer-{layer.number}" # Ensure uniqueness counter = 1 original_slug = new_slug while NarratorLayer.objects.filter(slug=new_slug).exclude(pk=layer.pk).exists(): new_slug = f"{original_slug}-{counter}" counter += 1 layer.slug = new_slug layer.save(update_fields=['slug']) fixed_count += 1 self.stdout.write(f' ✓ Fixed layer {layer.pk} (number={layer.number}): "{new_slug}"') except Exception as e: self.stdout.write(self.style.ERROR(f' ✗ Error fixing layer {row_id}: {str(e)}')) self.stdout.write(self.style.SUCCESS(f'Fixed {fixed_count} NarratorLayer records')) self.stdout.write('Fixing TransmitterReliability duplicates...') # Fix TransmitterReliability empty and duplicate slugs empty_reliability = TransmitterReliability.objects.filter(Q(slug__isnull=True) | Q(slug='') | Q(slug=' ')) for record in empty_reliability: try: if record.title and isinstance(record.title, list) and len(record.title) > 0: text = record.title[0].get('text', '').strip() if text: new_slug = slugify(text) else: from datetime import datetime new_slug = f"reliability-{datetime.now().strftime('%Y%m%d%H%M%S%f')}" else: from datetime import datetime new_slug = f"reliability-{datetime.now().strftime('%Y%m%d%H%M%S%f')}" except: from datetime import datetime new_slug = f"reliability-{datetime.now().strftime('%Y%m%d%H%M%S%f')}" counter = 1 original_slug = new_slug while TransmitterReliability.objects.filter(slug=new_slug).exclude(pk=record.pk).exists(): new_slug = f"{original_slug}-{counter}" counter += 1 record.slug = new_slug record.save(update_fields=['slug']) self.stdout.write(f' Fixed reliability {record.pk}: "{new_slug}"') # Fix duplicates duplicates = TransmitterReliability.objects.values('slug').annotate(count=Count('id')).filter(count__gt=1) for dup in duplicates: slug_value = dup['slug'] records = list(TransmitterReliability.objects.filter(slug=slug_value)) for i, record in enumerate(records): if i == 0: continue from datetime import datetime new_slug = f"{slug_value}-{i}-{datetime.now().strftime('%H%M%S%f')}" counter = 1 original_slug = new_slug while TransmitterReliability.objects.filter(slug=new_slug).exclude(pk=record.pk).exists(): new_slug = f"{original_slug}-{counter}" counter += 1 record.slug = new_slug record.save(update_fields=['slug']) self.stdout.write(f' Fixed duplicate reliability: "{new_slug}"') self.stdout.write('Fixing OpinionStatus duplicates...') # Fix OpinionStatus empty and duplicate slugs empty_opinion = OpinionStatus.objects.filter(Q(slug__isnull=True) | Q(slug='') | Q(slug=' ')) for record in empty_opinion: try: if record.title and isinstance(record.title, list) and len(record.title) > 0: text = record.title[0].get('text', '').strip() if text: new_slug = slugify(text) else: from datetime import datetime new_slug = f"opinion-{datetime.now().strftime('%Y%m%d%H%M%S%f')}" else: from datetime import datetime new_slug = f"opinion-{datetime.now().strftime('%Y%m%d%H%M%S%f')}" except: from datetime import datetime new_slug = f"opinion-{datetime.now().strftime('%Y%m%d%H%M%S%f')}" counter = 1 original_slug = new_slug while OpinionStatus.objects.filter(slug=new_slug).exclude(pk=record.pk).exists(): new_slug = f"{original_slug}-{counter}" counter += 1 record.slug = new_slug record.save(update_fields=['slug']) self.stdout.write(f' Fixed opinion status {record.pk}: "{new_slug}"') # Fix duplicates duplicates = OpinionStatus.objects.values('slug').annotate(count=Count('id')).filter(count__gt=1) for dup in duplicates: slug_value = dup['slug'] records = list(OpinionStatus.objects.filter(slug=slug_value)) for i, record in enumerate(records): if i == 0: continue from datetime import datetime new_slug = f"{slug_value}-{i}-{datetime.now().strftime('%H%M%S%f')}" counter = 1 original_slug = new_slug while OpinionStatus.objects.filter(slug=new_slug).exclude(pk=record.pk).exists(): new_slug = f"{original_slug}-{counter}" counter += 1 record.slug = new_slug record.save(update_fields=['slug']) self.stdout.write(f' Fixed duplicate opinion status: "{new_slug}"') self.stdout.write(self.style.SUCCESS('Data integrity fixes complete!')) 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): # Check if tag already exists existing_tags = HadisTag.objects.filter(title__contains=[{'language_code': 'ru', 'text': tag_name}]) if existing_tags.exists(): tag = existing_tags.first() created = False else: tag = HadisTag.objects.create( title=[{'language_code': 'ru', 'text': tag_name}], status=True ) created = 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 (slugs already fixed in Phase 0)""" # Create or get narrator layers - use filter().first() to avoid duplicates for layer_data in RUSSIAN_NARRATOR_LAYERS: # Try to find existing layer by number first layer = NarratorLayer.objects.filter(number=layer_data['number']).first() if layer: # Layer already exists - just use it self.stdout.write(f"Using existing layer {layer_data['number']}") self.narrator_layers.append(layer) else: # Create new layer - but be defensive try: # Use an inner atomic block so a single failure doesn't poison the outer transaction with transaction.atomic(): layer = NarratorLayer.objects.create( number=layer_data['number'], name=[{'language_code': 'ru', 'text': layer_data['name']}], description=[{'language_code': 'ru', 'text': layer_data['description']}] ) self.stdout.write(f"Created new layer {layer_data['number']}") self.narrator_layers.append(layer) except Exception as e: self.stdout.write(self.style.WARNING( f"Could not create layer {layer_data['number']}: {str(e)} - skipping" )) # If we don't have enough layers, try to get any existing ones if len(self.narrator_layers) < 3: self.stdout.write(self.style.WARNING('Not enough narrator layers, fetching all existing ones')) self.narrator_layers = list(NarratorLayer.objects.all()) self.created_counts['narrator_layers'] = len(self.narrator_layers) def create_reliability_statuses(self): """Create transmitter reliability statuses (duplicates already fixed in Phase 0)""" # Create or get reliability statuses - using filter().first() to avoid MultipleObjectsReturned for reliability_data in RUSSIAN_RELIABILITY_LEVELS: try: # Wrap in a savepoint so failures don't break the outer atomic transaction with transaction.atomic(): # Try to get by slug first reliability = TransmitterReliability.objects.filter(slug=reliability_data['slug']).first() if reliability: self.stdout.write(f"Using existing reliability: {reliability_data['slug']}") else: # Create new one reliability = TransmitterReliability.objects.create( slug=reliability_data['slug'], title=[{'language_code': 'ru', 'text': reliability_data['title']}], color=reliability_data['color'] ) self.stdout.write(f"Created new reliability: {reliability_data['slug']}") self.reliability_statuses.append(reliability) except Exception as e: self.stdout.write(self.style.ERROR( f"Error with reliability status {reliability_data['slug']}: {str(e)}" )) self.created_counts['reliability_statuses'] = len(self.reliability_statuses) def create_opinion_statuses(self): """Create opinion statuses (duplicates already fixed in Phase 0)""" # Create or get opinion statuses - using filter().first() to avoid MultipleObjectsReturned for opinion_data in RUSSIAN_OPINION_STATUSES: try: # Wrap in a savepoint so failures don't break the outer atomic transaction with transaction.atomic(): # Try to get by slug first opinion_status = OpinionStatus.objects.filter(slug=opinion_data['slug']).first() if opinion_status: self.stdout.write(f"Using existing opinion status: {opinion_data['slug']}") else: # Create new one opinion_status = OpinionStatus.objects.create( slug=opinion_data['slug'], title=[{'language_code': 'ru', 'text': opinion_data['title']}], color=opinion_data['color'] ) self.stdout.write(f"Created new opinion status: {opinion_data['slug']}") self.opinion_statuses.append(opinion_status) except Exception as e: self.stdout.write(self.style.ERROR( f"Error with opinion status {opinion_data['slug']}: {str(e)}" )) 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 # Generate father name from first word of a random name random_father_full_name = random.choice(RUSSIAN_TRANSMITTER_NAMES) father_name = random_father_full_name.split()[0] if ' ' in random_father_full_name else 'Абдуллах' try: # Savepoint per transmitter so a single bad row doesn't poison the outer atomic transaction with transaction.atomic(): transmitter = Transmitters.objects.create( full_name=[{'language_code': 'ru', 'text': f"{name} ибн {father_name}"}], 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) if self.reliability_statuses else None, 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) except Exception as e: self.stdout.write(self.style.WARNING(f"Skipping transmitter create due to error: {str(e)}")) continue # Add opinions for some transmitters if random.random() > 0.5: for _ in range(random.randint(1, 3)): try: with transaction.atomic(): 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 ) except Exception as e: self.stdout.write(self.style.WARNING(f"Skipping TransmitterOpinion due to error: {str(e)}")) # Add original texts for some transmitters if random.random() > 0.7: try: with transaction.atomic(): 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)}] ) except Exception as e: self.stdout.write(self.style.WARNING(f"Skipping TransmitterOriginalText due to error: {str(e)}")) self.created_counts['transmitters'] = count def create_books_and_authors(self): """Create books and authors""" from django.utils.text import slugify # Create authors - check for existing ones first for author_name in RUSSIAN_AUTHOR_NAMES[:15]: try: # Savepoint: do not poison the outer atomic transaction on a single failure with transaction.atomic(): # Check if author with this name already exists existing_author = None all_authors = BookAuthor.objects.all() for auth in all_authors: if auth.name and isinstance(auth.name, list) and len(auth.name) > 0: if auth.name[0].get('text', '') == author_name: existing_author = auth break if existing_author: author = existing_author self.stdout.write(f"Using existing author: {author_name}") else: author = BookAuthor.objects.create( name=[{'language_code': 'ru', 'text': author_name}] ) self.stdout.write(f"Created new author: {author_name}") self.authors.append(author) except Exception as e: self.stdout.write(self.style.ERROR( f"Error creating author {author_name}: {str(e)}" )) # Create books - check for existing ones first for book_title in RUSSIAN_BOOK_TITLES[:20]: try: # Savepoint: do not poison the outer atomic transaction on a single failure with transaction.atomic(): # Generate slug to check for existing book expected_slug = slugify(book_title, allow_unicode=True) # Try to find existing book by slug or title book = BookReference.objects.filter(slug=expected_slug).first() if not book: # Check by title as fallback all_books = BookReference.objects.all() for bk in all_books: if bk.title and isinstance(bk.title, list) and len(bk.title) > 0: if bk.title[0].get('text', '') == book_title: book = bk break if book: self.stdout.write(f"Using existing book: {book_title}") else: book = BookReference.objects.create( title=[{'language_code': 'ru', 'text': book_title}], description=[{'language_code': 'ru', 'text': f"Классическое исламское произведение - {book_title}"}] ) self.stdout.write(f"Created new book: {book_title}") # Add random authors if we have any if self.authors and book.authors.count() == 0: num_authors = min(random.randint(1, 2), len(self.authors)) book.authors.add(*random.sample(self.authors, num_authors)) self.books.append(book) except Exception as e: self.stdout.write(self.style.ERROR( f"Error creating book {book_title}: {str(e)}" )) 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 if self.tags: num_tags = min(random.randint(2, 5), len(self.tags)) hadis.tags.add(*random.sample(self.tags, num_tags)) # 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'))