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.
 
 

133 lines
5.2 KiB

import os
import random
from django.core.management.base import BaseCommand
from django.core.files import File
from django.core.files.base import ContentFile
from django.conf import settings
from django.db import transaction
# REMEMBER: Change 'your_app' to your actual app name
from apps.hadis.models.hadis import Hadis, HadisReference, ReferenceImage
from apps.hadis.models.reference import BookReference
class Command(BaseCommand):
help = 'Seeds HadisReferences ensuring every Book has 2+ hadiths AND every Hadith has 1+ reference.'
def handle(self, *args, **kwargs):
self.stdout.write(self.style.WARNING('--- Starting Cleanup ---'))
# 1. DELETE PREVIOUS DATA
deleted_imgs_count, _ = ReferenceImage.objects.all().delete()
deleted_refs_count, _ = HadisReference.objects.all().delete()
self.stdout.write(self.style.SUCCESS(f'Deleted {deleted_imgs_count} old ReferenceImages.'))
self.stdout.write(self.style.SUCCESS(f'Deleted {deleted_refs_count} old HadisReferences.'))
self.stdout.write('------------------------')
# 2. Setup Paths
self.base_image_path = os.path.join(settings.BASE_DIR, 'seeds', 'images')
self.image_files = [f'ref{i}.png' for i in range(1, 5)]
# Verify images
for img_name in self.image_files:
full_path = os.path.join(self.base_image_path, img_name)
if not os.path.exists(full_path):
self.stdout.write(self.style.ERROR(f'CRITICAL ERROR: Image not found at {full_path}'))
return
# 3. Fetch Data
books = list(BookReference.objects.all())
hadiths = list(Hadis.objects.all())
if not books or not hadiths:
self.stdout.write(self.style.ERROR('Missing Books or Hadiths in DB.'))
return
self.stdout.write('--- Starting Seeding ---')
self.counter_refs = 0
self.counter_imgs = 0
# Track which Hadith IDs have been covered
covered_hadith_ids = set()
# ==========================================
# PHASE 1: Satisfy Book Constraint
# "Each book must relate to at least 2 hadith"
# ==========================================
self.stdout.write("Phase 1: Linking Books to Hadiths...")
for book in books:
# Pick 2 random hadiths for this book
# We use distinct logic if we want to ensure we don't pick the same one twice for one book
selected_hadiths = random.sample(hadiths, k=min(len(hadiths), 2))
for hadis_obj in selected_hadiths:
self._create_reference_chain(hadis_obj, book)
covered_hadith_ids.add(hadis_obj.id)
# ==========================================
# PHASE 2: Satisfy Hadith Constraint
# "Each hadith must have a hadith reference object"
# ==========================================
self.stdout.write("Phase 2: Checking for orphan Hadiths...")
for hadis_obj in hadiths:
if hadis_obj.id not in covered_hadith_ids:
# This hadith was skipped in Phase 1.
# We must assign it to a Book (Reference).
# Pick a random book to associate with
random_book = random.choice(books)
self._create_reference_chain(hadis_obj, random_book)
covered_hadith_ids.add(hadis_obj.id)
self.stdout.write(self.style.SUCCESS(
f'DONE: Created {self.counter_refs} HadisReferences (covering {len(covered_hadith_ids)} Hadiths) and {self.counter_imgs} Images.'
))
def _create_reference_chain(self, hadis_obj, book_obj):
"""
Helper to create the Reference and its Images
"""
# Create the HadisReference
hadis_ref = HadisReference.objects.create(
hadis=hadis_obj,
book_reference=book_obj,
description=[
{'language_code': 'en', 'text': f'Reference for {book_obj.title[0].get("text", "Book")} - Hadith {hadis_obj.number}'},
{'language_code': 'ar', 'text': 'وصف مرجعي'}
]
)
self.counter_refs += 1
# Create Images for this Reference
self._create_images_for_ref(hadis_ref)
def _create_images_for_ref(self, hadis_ref):
"""
Helper to create 2 images for a specific HadisReference
"""
selected_images = random.sample(self.image_files, 2)
for priority_index, img_name in enumerate(selected_images):
img_path = os.path.join(self.base_image_path, img_name)
# Read file safely
with open(img_path, 'rb') as f:
file_content = f.read()
ref_img = ReferenceImage(
reference=hadis_ref,
priority=priority_index
)
# Assign content without auto-saving
ref_img.thumbnail.save(img_name, ContentFile(file_content), save=False)
try:
# Explicit save to handle your custom model logic / signals
ref_img.save()
self.counter_imgs += 1
except Exception as e:
self.stdout.write(self.style.ERROR(f"Failed to save image {img_name}: {e}"))