4 changed files with 229 additions and 0 deletions
-
50apps/hadis/management/commands/generate_author_slug.py
-
57apps/hadis/management/commands/link_authors_to_narrators.py
-
75apps/hadis/management/commands/seed_hadis_chains.py
-
47apps/hadis/management/commands/seed_opinion_scholars.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!" |
||||
|
) |
||||
|
) |
||||
@ -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!" |
||||
|
) |
||||
|
) |
||||
@ -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!" |
||||
|
) |
||||
|
) |
||||
@ -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)!" |
||||
|
) |
||||
|
) |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue