import os import random import urllib.request from django.core.management.base import BaseCommand from django.db import transaction from django.core.files.base import ContentFile from apps.hadis.models import ( BookReference, BookAuthor, BookEdition, BookVolume, BookResearcher, BookEditor, ) class Command(BaseCommand): help = 'Generates randomized Editions and Volumes (with sample cover image and PDF file) for all BookReferences.' def add_arguments(self, parser): parser.add_argument( '--clear', action='store_true', default=True, help='Clear existing BookEditions and BookVolumes before generating (default: True)', ) parser.add_argument( '--keep-existing', action='store_true', help='Do not clear existing data, only add/modify', ) def _fetch_sample_assets(self): """ Downloads a lightweight Islamic cover image and sample PDF from the web. Falls back to generated placeholder bytes if network request fails. """ self.stdout.write("Downloading sample Islamic book image and sample PDF...") image_url = "https://images.unsplash.com/photo-1609599006353-e629aaabfeae?w=500&auto=format&fit=crop&q=80" image_bytes = None try: req = urllib.request.Request(image_url, headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}) with urllib.request.urlopen(req, timeout=15) as resp: image_bytes = resp.read() self.stdout.write(self.style.SUCCESS(f"Downloaded sample cover image ({len(image_bytes)} bytes).")) except Exception as e: self.stdout.write(self.style.WARNING(f"Failed to download image ({e}), generating a local fallback image...")) from PIL import Image, ImageDraw import io img = Image.new('RGB', (400, 600), color='#1e293b') draw = ImageDraw.Draw(img) draw.rectangle([20, 20, 380, 580], outline='#e2e8f0', width=3) buf = io.BytesIO() img.save(buf, format='JPEG') image_bytes = buf.getvalue() pdf_url = "https://raw.githubusercontent.com/mozilla/pdf.js/master/examples/learning/helloworld.pdf" pdf_bytes = None try: req = urllib.request.Request(pdf_url, headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}) with urllib.request.urlopen(req, timeout=15) as resp: pdf_bytes = resp.read() self.stdout.write(self.style.SUCCESS(f"Downloaded sample PDF document ({len(pdf_bytes)} bytes).")) except Exception as e: self.stdout.write(self.style.WARNING(f"Failed to download PDF ({e}), generating a fallback PDF...")) from reportlab.pdfgen import canvas import io buf = io.BytesIO() p = canvas.Canvas(buf) p.drawString(100, 750, "Sample Islamic Hadith Reference Document") p.drawString(100, 720, "This is a lightweight sample volume file.") p.showPage() p.save() pdf_bytes = buf.getvalue() return image_bytes, pdf_bytes def handle(self, *args, **options): clear_existing = not options.get('keep_existing', False) references = list(BookReference.objects.all()) authors = list(BookAuthor.objects.all()) if not references: self.stdout.write(self.style.ERROR("No BookReference found in the database.")) return self.stdout.write(f"Found {len(references)} BookReferences and {len(authors)} BookAuthors.") if clear_existing: self.stdout.write(self.style.WARNING("Clearing existing BookEditions and BookVolumes...")) BookVolume.objects.all().delete() BookEdition.objects.all().delete() BookResearcher.objects.all().delete() BookEditor.objects.all().delete() # Download or prepare sample assets image_bytes, pdf_bytes = self._fetch_sample_assets() # Publishers pool publishers_pool = [ [ {"language_code": "fa", "text": "دار الحديث"}, {"language_code": "ar", "text": "دار الحديث للطباعة والنشر"}, {"language_code": "en", "text": "Dar al-Hadith Publications"}, ], [ {"language_code": "fa", "text": "مؤسسة آل البيت (ع) لإحياء التراث"}, {"language_code": "ar", "text": "مؤسسة آل البيت عليهم السلام لإحياء التراث"}, {"language_code": "en", "text": "Aal al-Bayt Institute for Heritage Revival"}, ], [ {"language_code": "fa", "text": "دار الكتب الإسلامية"}, {"language_code": "ar", "text": "دار الكتب الإسلامية"}, {"language_code": "en", "text": "Dar al-Kutub al-Islamiyya"}, ], [ {"language_code": "fa", "text": "منشورات الشريف الرضي"}, {"language_code": "ar", "text": "منشورات الشريف الرضي"}, {"language_code": "en", "text": "Al-Sharif al-Razi Publications"}, ], [ {"language_code": "fa", "text": "مؤسسة النشر الإسلامي"}, {"language_code": "ar", "text": "مؤسسة النشر الإسلامي التابعة لجماعة المدرسين"}, {"language_code": "en", "text": "Islamic Publishing Foundation"}, ], [ {"language_code": "fa", "text": "مؤسسة البلاغ"}, {"language_code": "ar", "text": "مؤسسة البلاغ للطباعة والنشر والتوزيع"}, {"language_code": "en", "text": "Al-Balagh Foundation"}, ], ] cities_pool = [ [{"language_code": "fa", "text": "قم"}, {"language_code": "ar", "text": "قم المقدسة"}, {"language_code": "en", "text": "Qom"}], [{"language_code": "fa", "text": "بیروت"}, {"language_code": "ar", "text": "بيروت"}, {"language_code": "en", "text": "Beirut"}], [{"language_code": "fa", "text": "نجف"}, {"language_code": "ar", "text": "النجف الأشرف"}, {"language_code": "en", "text": "Najaf"}], [{"language_code": "fa", "text": "تهران"}, {"language_code": "ar", "text": "طهران"}, {"language_code": "en", "text": "Tehran"}], [{"language_code": "fa", "text": "مشهد"}, {"language_code": "ar", "text": "مشهد المقدسة"}, {"language_code": "en", "text": "Mashhad"}], ] countries_pool = [ [{"language_code": "fa", "text": "ایران"}, {"language_code": "ar", "text": "إيران"}, {"language_code": "en", "text": "Iran"}], [{"language_code": "fa", "text": "لبنان"}, {"language_code": "ar", "text": "لبنان"}, {"language_code": "en", "text": "Lebanon"}], [{"language_code": "fa", "text": "عراق"}, {"language_code": "ar", "text": "العراق"}, {"language_code": "en", "text": "Iraq"}], ] edition_names = ["چاپ اول", "چاپ دوم", "چاپ سوم", "طبعة ثانية منقحة", "طبعة أولى محققة", "First Revised Edition", "Second Edition"] years_pool = ["1418 هـ.ق", "1422 هـ.ق", "1429 هـ.ق", "1436 هـ.ق", "1441 هـ.ق", "1385 ش", "1392 ش", "1398 ش", "1402 ش"] total_editions_created = 0 total_volumes_created = 0 total_researchers_created = 0 total_editors_created = 0 self.stdout.write("Generating Editions and Volumes for BookReferences...") with transaction.atomic(): for ref in references: # Random choice: whether this reference has editions or only direct volumes has_editions = random.choice([True, False]) ref.has_editions = has_editions ref.save(update_fields=['has_editions']) if has_editions: num_editions = random.randint(1, 3) for ed_idx in range(1, num_editions + 1): num_volumes = random.randint(3, 5) pub = random.choice(publishers_pool) city = random.choice(cities_pool) country = random.choice(countries_pool) ed_num = random.choice(edition_names) year = random.choice(years_pool) isbn = f"978-964-{random.randint(100, 999)}-{random.randint(10, 99)}-{random.randint(0, 9)}" edition = BookEdition.objects.create( book_reference=ref, publisher=pub, city_of_publication=city, country_of_publication=country, edition_number=f"{ed_num} ({ed_idx})", year_of_publication=year, number_of_volumes=num_volumes, isbn=isbn, notes=[ {"language_code": "fa", "text": f"نسخه معتبر تصحیح شده با مقابله با نسخ خطی {ed_idx}"}, {"language_code": "en", "text": f"Verified critical edition compared against manuscripts {ed_idx}"} ], source_url=f"https://lib.eshia.ir/{ref.id}/{edition_names[0]}" ) total_editions_created += 1 # Assign random researchers and editors from existing authors if authors: sample_researchers = random.sample(authors, min(len(authors), random.randint(1, 2))) for author in sample_researchers: BookResearcher.objects.create( book_edition=edition, author=author ) total_researchers_created += 1 sample_editors = random.sample(authors, min(len(authors), random.randint(1, 2))) for author in sample_editors: BookEditor.objects.create( book_edition=edition, author=author ) total_editors_created += 1 # Create 3 to 5 volumes for this edition for vol_idx in range(1, num_volumes + 1): vol = BookVolume( book_reference=ref, edition=edition, title=f"جلد {vol_idx}", ) vol.image.save( f"ref_{ref.id}_ed_{edition.id}_vol_{vol_idx}_cover.jpg", ContentFile(image_bytes), save=False ) vol.file.save( f"ref_{ref.id}_ed_{edition.id}_vol_{vol_idx}.pdf", ContentFile(pdf_bytes), save=False ) vol.save() total_volumes_created += 1 else: # Direct volumes without editions num_volumes = random.randint(3, 5) for vol_idx in range(1, num_volumes + 1): vol = BookVolume( book_reference=ref, edition=None, title=f"جلد {vol_idx}", ) vol.image.save( f"ref_{ref.id}_vol_{vol_idx}_cover.jpg", ContentFile(image_bytes), save=False ) vol.file.save( f"ref_{ref.id}_vol_{vol_idx}.pdf", ContentFile(pdf_bytes), save=False ) vol.save() total_volumes_created += 1 self.stdout.write( self.style.SUCCESS( f"\n--- Seeding Completed Successfully ---\n" f"Processed {len(references)} BookReferences:\n" f" - Total BookEditions created: {total_editions_created}\n" f" - Total BookVolumes created: {total_volumes_created}\n" f" - Total Researchers assigned: {total_researchers_created}\n" f" - Total Editors assigned: {total_editors_created}\n" f" - Cover image & PDF attached to all volumes." ) )