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
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()
|