diff --git a/apps/hadis/management/commands/generate_author_slug.py b/apps/hadis/management/commands/generate_author_slug.py new file mode 100644 index 0000000..3c9a624 --- /dev/null +++ b/apps/hadis/management/commands/generate_author_slug.py @@ -0,0 +1,50 @@ +# backend/apps/hadis/management/commands/generate_author_slugs.py + +from django.core.management.base import BaseCommand +from apps.hadis.models.reference import BookAuthor + +class Command(BaseCommand): + help = 'Generates missing slugs for BookAuthor records.' + + def add_arguments(self, parser): + # اضافه کردن یک قابلیت اختیاری برای ساخت مجدد تمام اسلاگ‌ها + parser.add_argument( + '--all', + action='store_true', + help='Regenerate slugs for ALL authors, even if they already have one.', + ) + + def handle(self, *args, **options): + regenerate_all = options['all'] + + if regenerate_all: + # گرفتن همه نویسنده‌ها + authors = BookAuthor.objects.all() + self.stdout.write(self.style.WARNING(f"Regenerating slugs for ALL {authors.count()} authors...")) + else: + # گرفتن نویسنده‌هایی که اسلاگ ندارند یا اسلاگشان خالی است + authors = BookAuthor.objects.filter(slug__isnull=True) | BookAuthor.objects.filter(slug='') + self.stdout.write(self.style.WARNING(f"Generating slugs for {authors.count()} authors without a slug...")) + + if not authors.exists(): + self.stdout.write(self.style.SUCCESS("All authors already have slugs. Nothing to do!")) + return + + updated_count = 0 + for author in authors: + if regenerate_all: + author.slug = '' # خالی کردن اسلاگ تا متد save مجبور به ساخت مجدد شود + + # صدا زدن متد save باعث می‌شود منطق اسلاگ‌سازِ داخل مدل شما به صورت خودکار اجرا شود + author.save() + updated_count += 1 + + # چاپ لاگ پیشرفت برای هر 100 رکورد + if updated_count % 100 == 0: + self.stdout.write(f"Processed {updated_count} authors...") + + self.stdout.write( + self.style.SUCCESS( + f"\n🎉 Successfully generated/updated slugs for {updated_count} BookAuthors!" + ) + ) \ No newline at end of file diff --git a/apps/hadis/management/commands/link_authors_to_narrators.py b/apps/hadis/management/commands/link_authors_to_narrators.py new file mode 100644 index 0000000..b725520 --- /dev/null +++ b/apps/hadis/management/commands/link_authors_to_narrators.py @@ -0,0 +1,57 @@ +# backend/apps/hadis/management/commands/link_authors_to_narrators.py + +import random +from django.core.management.base import BaseCommand +from django.db import transaction +from apps.hadis.models.reference import BookAuthor +from apps.hadis.models.transmitter import Transmitters + +class Command(BaseCommand): + help = 'Randomly links BookAuthors to Transmitters (Narrators) for testing.' + + def handle(self, *args, **options): + self.stdout.write(self.style.WARNING("Starting to link BookAuthors to random Transmitters...")) + + # دریافت تمام نویسنده‌ها + authors = list(BookAuthor.objects.all()) + + # دریافت تمام راویانی که هنوز به هیچ نویسنده‌ای متصل نشده‌اند + # استفاده از book_author_profile__isnull=True برای جلوگیری از ارور OneToOne + available_narrators = list(Transmitters.objects.filter(book_author_profile__isnull=True)) + + if not authors: + self.stdout.write(self.style.ERROR("No BookAuthors found in the database.")) + return + + if not available_narrators: + self.stdout.write(self.style.ERROR("No unassigned Transmitters found in the database.")) + return + + # بُر زدن (Shuffle) لیست راویان برای رندوم شدن واقعی + random.shuffle(available_narrators) + + linked_count = 0 + + # استفاده از ترنزکشن برای سرعت بالاتر و جلوگیری از ذخیره ناقص در صورت بروز خطا + with transaction.atomic(): + for author in authors: + # اگر راوی خالیِ دیگری نمانده بود، حلقه را متوقف می‌کنیم + if not available_narrators: + self.stdout.write(self.style.WARNING( + f"Ran out of available Transmitters. Stopped after linking {linked_count} authors." + )) + break + + # برداشتن یک راوی رندوم از لیست و اتصال آن به نویسنده + random_narrator = available_narrators.pop() + author.related_narrator = random_narrator + + # برای بهینه‌سازی، فقط همین یک فیلد را در دیتابیس آپدیت می‌کنیم + author.save(update_fields=['related_narrator']) + linked_count += 1 + + self.stdout.write( + self.style.SUCCESS( + f"\n🎉 Successfully linked {linked_count} BookAuthors to random Transmitters!" + ) + ) \ No newline at end of file diff --git a/apps/hadis/management/commands/seed_hadis_chains.py b/apps/hadis/management/commands/seed_hadis_chains.py new file mode 100644 index 0000000..814068b --- /dev/null +++ b/apps/hadis/management/commands/seed_hadis_chains.py @@ -0,0 +1,75 @@ +# backend/apps/hadis/management/commands/seed_hadis_chains.py + +import random +from django.core.management.base import BaseCommand +from django.db import transaction +from apps.hadis.models import Hadis, Transmitters, HadisTransmitter, NarratorLayer, TransmitterReliability + +class Command(BaseCommand): + help = 'Seeds random transmission chains (HadisTransmitter) for all existing Hadiths.' + + def handle(self, *args, **options): + self.stdout.write(self.style.WARNING("Starting to seed random transmission chains...")) + + # دریافت تمام دیتاهای پایه + hadiths = list(Hadis.objects.all()) + narrators = list(Transmitters.objects.all()) + layers = list(NarratorLayer.objects.all()) + reliabilities = list(TransmitterReliability.objects.all()) + + # بررسی وجود دیتای کافی + if not hadiths: + self.stdout.write(self.style.ERROR("No Hadiths found. Please seed Hadiths first.")) + return + + if len(narrators) < 4: + self.stdout.write(self.style.ERROR("Not enough Transmitters found. Please add at least 4 narrators.")) + return + + # پاک کردن تمام زنجیره‌های روایی قبلی برای جلوگیری از خطای Unique Constraint + self.stdout.write("Clearing old transmission chains...") + HadisTransmitter.objects.all().delete() + + links_to_create = [] + + # ساخت زنجیره‌ها + for hadis in hadiths: + # هر حدیث بین 2 تا 3 لایه/زنجیره (Chain) داشته باشد + num_chains = random.randint(2, 3) + + for chain_idx in range(num_chains): + # هر زنجیره بین 4 تا 6 راوی داشته باشد + num_narrators = random.randint(4, min(6, len(narrators))) + + # انتخاب رندوم چند راوی برای این زنجیره بدون تکرار + chain_narrators = random.sample(narrators, num_narrators) + + for order_idx, narrator in enumerate(chain_narrators): + + # انتخاب رندوم لایه و وضعیت (اگر در دیتابیس وجود داشته باشند) + random_layer = random.choice(layers) if layers else None + random_status = random.choice(reliabilities) if reliabilities else None + + link = HadisTransmitter( + hadis=hadis, + transmitter=narrator, + chain_index=chain_idx, + order=order_idx, # ترتیب قرارگیری راوی در این زنجیره + narrator_layer=random_layer, + status=random_status, + is_gap=random.choice([True, False, False, False]) # احتمال کم برای گپ (انقطاع سند) + ) + links_to_create.append(link) + + # ذخیره دسته‌جمعی (Bulk Create) برای پرفورمنس بسیار بالاتر + with transaction.atomic(): + # برای جلوگیری از محدودیت حافظه، در دسته‌های 1000 تایی ذخیره می‌کنیم + batch_size = 1000 + for i in range(0, len(links_to_create), batch_size): + HadisTransmitter.objects.bulk_create(links_to_create[i:i + batch_size]) + + self.stdout.write( + self.style.SUCCESS( + f"\n🎉 Successfully created {len(links_to_create)} random narrator links across {len(hadiths)} Hadiths!" + ) + ) \ No newline at end of file diff --git a/apps/hadis/management/commands/seed_opinion_scholars.py b/apps/hadis/management/commands/seed_opinion_scholars.py new file mode 100644 index 0000000..0d99500 --- /dev/null +++ b/apps/hadis/management/commands/seed_opinion_scholars.py @@ -0,0 +1,47 @@ +# backend/apps/hadis/management/commands/seed_opinion_scholars.py + +import random +from django.core.management.base import BaseCommand +from django.db import transaction +from apps.hadis.models import TransmitterOpinion, BookAuthor + +class Command(BaseCommand): + help = 'Randomly assigns BookAuthors to existing TransmitterOpinions as scholars.' + + def handle(self, *args, **options): + self.stdout.write(self.style.WARNING("Starting to link opinions to random scholars...")) + + # دریافت تمام رکوردها + opinions = list(TransmitterOpinion.objects.all()) + authors = list(BookAuthor.objects.all()) + + if not opinions: + self.stdout.write(self.style.ERROR("No TransmitterOpinions found in the database.")) + return + + if not authors: + self.stdout.write(self.style.ERROR("No BookAuthors found. Please add some authors first.")) + return + + opinions_to_update = [] + + # تخصیص رندوم نویسنده‌ها به نظرات + for opinion in opinions: + random_scholar = random.choice(authors) + opinion.scholar = random_scholar + opinions_to_update.append(opinion) + + # آپدیت گروهی (Bulk Update) برای پرفورمنس بالا + with transaction.atomic(): + batch_size = 1000 + for i in range(0, len(opinions_to_update), batch_size): + TransmitterOpinion.objects.bulk_update( + opinions_to_update[i:i + batch_size], + ['scholar'] # فقط فیلد scholar آپدیت می‌شود + ) + + self.stdout.write( + self.style.SUCCESS( + f"\n🎉 Successfully linked {len(opinions_to_update)} TransmitterOpinions to random BookAuthors (Scholars)!" + ) + ) \ No newline at end of file