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.
 
 
 
 
 

240 lines
9.4 KiB

import os
import sys
import random
import django
# Setup environment
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.stdout.reconfigure(encoding='utf-8')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.base')
django.setup()
from django.db import transaction
from django.db.models.signals import post_save, post_delete, m2m_changed
from apps.hadis.signals import clear_hadis_cache, clear_hadis_cache_on_m2m, invalidate_hadis_cache
from apps.hadis.models import (
BookReference, BookEdition, BookVolume,
HadisReference, HadisInterpretation, InterpretationReference,
HadisCorrection, CorrectionReference
)
from apps.hadis.models.transmitter import OriginalTextReference
# Disconnect cache signals during bulk population for high performance
post_save.disconnect(clear_hadis_cache)
post_delete.disconnect(clear_hadis_cache)
m2m_changed.disconnect(clear_hadis_cache_on_m2m)
SAMPLE_PUBLISHERS = [
[
{'text': 'دار الحديث', 'language_code': 'fa'},
{'text': 'دار الحديث للطباعة والنشر', 'language_code': 'ar'},
{'text': 'Dar al-Hadith Publications', 'language_code': 'en'}
],
[
{'text': 'دار الكتب الإسلامية', 'language_code': 'fa'},
{'text': 'دار الكتب الإسلامية', 'language_code': 'ar'},
{'text': 'Dar al-Kutub al-Islamiyya', 'language_code': 'en'}
],
[
{'text': 'مؤسسة النشر الإسلامي', 'language_code': 'fa'},
{'text': 'مؤسسة النشر الإسلامي التابعة لجماعة المدرسين', 'language_code': 'ar'},
{'text': 'Islamic Publishing Foundation', 'language_code': 'en'}
],
[
{'text': 'مؤسسة البلاغ', 'language_code': 'fa'},
{'text': 'مؤسسة البلاغ للطباعة والنشر والتوزيع', 'language_code': 'ar'},
{'text': 'Al-Balagh Foundation', 'language_code': 'en'}
],
[
{'text': 'دار الكتب العلمية', 'language_code': 'fa'},
{'text': 'دار الكتب العلمية', 'language_code': 'ar'},
{'text': 'Dar al-Kutub al-Ilmiyya', 'language_code': 'en'}
],
[
{'text': 'مؤسسة آل البيت (ع) لإحياء التراث', 'language_code': 'fa'},
{'text': 'مؤسسة آل البيت عليهم السلام لإحياء التراث', 'language_code': 'ar'},
{'text': 'Aal al-Bayt Institute', 'language_code': 'en'}
],
]
def is_empty_value(val):
if val is None:
return True
s = str(val).strip()
return s in ['', '0', '00', 'None', 'null', 'nan']
def ensure_book_editions_and_volumes():
"""Ensure every BookReference has at least 1 BookEdition and 1 BookVolume."""
all_books = list(BookReference.objects.prefetch_related('editions', 'volumes').all())
print(f"Checking {len(all_books)} books for editions and volumes...", flush=True)
editions_to_create = []
books_needing_editions = []
for book in all_books:
editions = list(book.editions.all())
if not editions:
pub = random.choice(SAMPLE_PUBLISHERS)
editions_to_create.append(BookEdition(
book_reference=book,
publisher=pub,
edition_number='طبعة أولى (1)',
year_of_publication='1441',
number_of_volumes=4
))
books_needing_editions.append(book)
if editions_to_create:
created = BookEdition.objects.bulk_create(editions_to_create)
print(f"Created {len(created)} default editions.", flush=True)
else:
print("All books already have editions.", flush=True)
# Re-fetch or assign volumes
all_books = list(BookReference.objects.prefetch_related('editions', 'volumes').all())
volumes_to_create = []
for book in all_books:
volumes = list(book.volumes.all())
if not volumes:
editions = list(book.editions.all())
ed = editions[0] if editions else None
for vol_num in range(1, 5):
volumes_to_create.append(BookVolume(
book_reference=book,
edition=ed,
title=f"جلد {vol_num}"
))
if volumes_to_create:
created_vols = BookVolume.objects.bulk_create(volumes_to_create)
print(f"Created {len(created_vols)} default volumes.", flush=True)
else:
print("All books already have volumes.", flush=True)
def process_reference_queryset(model_class, model_name, all_books_map):
"""Update edition, book_volume, volume, pages, and hadith_number on all instances using bulk_update."""
qs = model_class.objects.select_related('book_reference', 'edition', 'book_volume').all()
total = qs.count()
print(f"\nProcessing {total} records of {model_name}...", flush=True)
if total == 0:
return
updated_count = 0
all_book_ids = list(all_books_map.keys())
if not all_book_ids:
print("Error: No books available in database!", flush=True)
return
items_to_update = []
has_hadith_number = hasattr(model_class, 'hadith_number')
update_fields = ['book_reference', 'edition', 'book_volume', 'volume', 'pages']
if has_hadith_number:
update_fields.append('hadith_number')
for ref in qs:
changed = False
# 1. Ensure book_reference is attached
book = ref.book_reference
if not book:
chosen_book_id = random.choice(all_book_ids)
book = all_books_map[chosen_book_id]['book']
ref.book_reference = book
changed = True
book_data = all_books_map.get(book.id)
if not book_data:
continue
book_editions = book_data['editions']
book_volumes = book_data['volumes']
# 2. Ensure edition (Publisher) is set
if not ref.edition and book_editions:
ref.edition = random.choice(book_editions)
changed = True
# 3. Ensure book_volume and volume text are set
if not ref.book_volume and book_volumes:
chosen_vol = random.choice(book_volumes)
ref.book_volume = chosen_vol
ref.volume = chosen_vol.title or f"جلد {random.randint(1, 4)}"
changed = True
elif not ref.volume:
ref.volume = f"جلد {random.randint(1, 4)}"
changed = True
# 4. Ensure pages is set to a valid random page number
if is_empty_value(ref.pages):
ref.pages = str(random.randint(15, 480))
changed = True
# 5. Ensure hadith_number is set to a valid random hadith number
if has_hadith_number:
if is_empty_value(ref.hadith_number):
ref.hadith_number = str(random.randint(45, 3450))
changed = True
if changed:
items_to_update.append(ref)
if len(items_to_update) >= 300:
model_class.objects.bulk_update(items_to_update, update_fields)
updated_count += len(items_to_update)
print(f" - Updated {updated_count}/{total} records...", flush=True)
items_to_update = []
if items_to_update:
model_class.objects.bulk_update(items_to_update, update_fields)
updated_count += len(items_to_update)
print(f"Completed {model_name}: {updated_count} / {total} records updated.", flush=True)
def main():
print("==================================================", flush=True)
print("STARTING REFERENCE METADATA POPULATION", flush=True)
print("==================================================", flush=True)
with transaction.atomic():
# Step 1: Ensure all books have editions and volumes
ensure_book_editions_and_volumes()
# Step 2: Cache book relations in memory for fast lookup
all_books_map = {}
for b in BookReference.objects.prefetch_related('editions', 'volumes').all():
all_books_map[b.id] = {
'book': b,
'editions': list(b.editions.all()),
'volumes': list(b.volumes.all()),
}
print(f"Cached {len(all_books_map)} books with their editions and volumes.", flush=True)
# Step 3: Update HadisReference (Arguments)
process_reference_queryset(HadisReference, "HadisReference (Arguments)", all_books_map)
# Step 4: Update InterpretationReference (Interpretations)
process_reference_queryset(InterpretationReference, "InterpretationReference (Interpretations)", all_books_map)
# Step 5: Update OriginalTextReference (Original Texts)
process_reference_queryset(OriginalTextReference, "OriginalTextReference (Original Texts)", all_books_map)
# Step 6: Update CorrectionReference (Corrections)
process_reference_queryset(CorrectionReference, "CorrectionReference (Corrections)", all_books_map)
# Invalidate cache once at the end
print("\nInvalidating API cache...", flush=True)
try:
invalidate_hadis_cache()
print("API cache invalidated successfully.", flush=True)
except Exception as e:
print(f"Cache invalidation note: {e}", flush=True)
print("\n==================================================", flush=True)
print("SUCCESS: ALL REFERENCES SUCCESSFULLY UPDATED!", flush=True)
print("==================================================", flush=True)
if __name__ == '__main__':
main()