Browse Source

Hadis transmitters chain fixed

fixed seed logic and removed the pagination.
master
Mohsen Taba 4 months ago
parent
commit
4ce8f457e1
  1. 122
      apps/hadis/management/commands/seed_hadis_transmitter.py
  2. 2
      apps/hadis/views/hadis.py

122
apps/hadis/management/commands/seed_hadis_transmitter.py

@ -1,93 +1,93 @@
import random
import time
from django.core.management.base import BaseCommand
from django.db import transaction
from django.db.models import Q
# REPLACE 'your_app' with your actual app name (e.g., apps.hadis.models)
# REPLACE 'your_app' with your actual app name
from apps.hadis.models import Hadis, Transmitters, NarratorLayer, HadisTransmitter
class Command(BaseCommand):
help = 'Seeds HadisTransmitter instances for ALL Hadis with 5+ transmitters spanning 2-3 layers'
help = 'Seeds HadisTransmitters: Multiple layers per Hadis, each with an independent chain of 5+ transmitters.'
def handle(self, *args, **options):
self.stdout.write("Starting Global HadisTransmitter seeding...")
self.stdout.write("Starting Global HadisTransmitter seeding (Layer-based Parallel Chains)...")
# ---------------------------------------------------------
# 1. Fetch ALL Objects
# ---------------------------------------------------------
# 1. Fetch Objects
layers = list(NarratorLayer.objects.all())
transmitters = list(Transmitters.objects.all())
# Fetch all Hadis records
hadis_qs = Hadis.objects.all()
# ---------------------------------------------------------
# 2. Validation
# ---------------------------------------------------------
if len(layers) < 3:
self.stdout.write(self.style.ERROR(f"Need at least 3 NarratorLayers to satisfy constraints, but found {len(layers)}."))
# 2. Critical Validation
# We need enough pool size. Minimum requirement: 2 layers * 5 transmitters = 10 unique people.
if len(layers) < 2:
self.stdout.write(self.style.ERROR(f"Error: Need at least 2 NarratorLayers, found {len(layers)}."))
return
if len(transmitters) < 5:
self.stdout.write(self.style.ERROR(f"Need at least 5 Transmitters to satisfy chain length, but found {len(transmitters)}."))
# If you haven't run the transmitter seeder yet, this might fail.
if len(transmitters) < 10:
self.stdout.write(self.style.ERROR(
f"Error: Found only {len(transmitters)} transmitters. "
"To satisfy '2 layers x 5 transmitters', you need at least 10 unique transmitters. "
"Please run the transmitter seeder command first."
))
return
if not hadis_qs.exists():
self.stdout.write(self.style.ERROR("No Hadis found in the database."))
self.stdout.write(self.style.ERROR("No Hadis found."))
return
total_hadis = hadis_qs.count()
self.stdout.write(f"Found {len(layers)} Layers, {len(transmitters)} Transmitters, and {total_hadis} Hadis.")
# ---------------------------------------------------------
# 3. Creation Loop
# ---------------------------------------------------------
created_links_count = 0
self.stdout.write(f"Found {len(layers)} Layers, {len(transmitters)} Transmitters. Processing {total_hadis} Hadiths...")
self.stdout.write("Beginning processing...")
# 3. Processing
created_links_count = 0
for i, hadis in enumerate(hadis_qs, 1):
# Progress indicator
if i % 100 == 0:
if i % 50 == 0:
self.stdout.write(f"Processing {i}/{total_hadis}...")
with transaction.atomic():
# Clean existing transmitters for this hadis to avoid duplicates/conflicts if re-running
# Remove this line if you want to APPEND to existing data instead of resetting
# A. Wipe existing connections for a clean slate
HadisTransmitter.objects.filter(hadis=hadis).delete()
# CONSTRAINT 1: Chain length must be at least 5 (let's do 5 to 7)
chain_length = random.randint(5, 7)
# B. Determine Structure
# Constraint: At least 2-3 layers
num_layers_to_use = random.randint(2, 3)
# Don't try to use more layers than exist in DB
num_layers_to_use = min(num_layers_to_use, len(layers))
selected_layers = random.sample(layers, num_layers_to_use)
# CONSTRAINT 2: Must have at least 2-3 narrator layers
target_unique_layers = random.randint(2, 3)
# Constraint: At least 5 transmitters per layer (let's say 5 to 7)
# We calculate total needed first to ensure we pick UNIQUE people for this specific Hadith
counts_per_layer = [random.randint(5, 7) for _ in range(num_layers_to_use)]
total_needed = sum(counts_per_layer)
# --- Logic to Select Transmitters and Layers ---
# A. Select Transmitters
selected_transmitters = random.sample(transmitters, chain_length)
# Safety: Ensure we don't ask for more than we have in the whole DB
if total_needed > len(transmitters):
self.stdout.write(self.style.WARNING(f"Hadis {hadis.id}: Not enough total transmitters for {num_layers_to_use} layers. Skipping."))
continue
# B. Select Layers
# First, pick the 'mandatory' unique layers to satisfy the constraint
mandatory_layers = random.sample(layers, target_unique_layers)
# Second, fill the remaining slots in the chain
remaining_slots = chain_length - target_unique_layers
# We can pick from ANY layer for the remaining slots (including the mandatory ones)
other_layers = [random.choice(layers) for _ in range(remaining_slots)]
# Combine and Shuffle
final_layers_pool = mandatory_layers + other_layers
random.shuffle(final_layers_pool)
# C. Select Transmitters
# We pick a unique pool for this Hadith so the same person isn't in 2 layers
pool = random.sample(transmitters, total_needed)
# D. Distribute and Create
cursor = 0
for layer_idx, layer in enumerate(selected_layers):
count = counts_per_layer[layer_idx]
# Slice the pool for this layer
layer_group = pool[cursor : cursor + count]
cursor += count
# --- Create Connections ---
for index, transmitter in enumerate(selected_transmitters):
HadisTransmitter.objects.create(
hadis=hadis,
transmitter=transmitter,
narrator_layer=final_layers_pool[index],
order=index,
# Check if transmitter has 'reliability' (ForeignKey) or if it's a direct field
status=transmitter.reliability if hasattr(transmitter, 'reliability') else None
)
created_links_count += 1
# Create Links with Independent Ordering (0, 1, 2...) for THIS layer
for order_index, transmitter in enumerate(layer_group):
HadisTransmitter.objects.create(
hadis=hadis,
transmitter=transmitter,
narrator_layer=layer,
order=order_index, # Resets to 0 for every layer!
status=transmitter.reliability if hasattr(transmitter, 'reliability') else None
)
created_links_count += 1
self.stdout.write(self.style.SUCCESS(f"Done! Created {created_links_count} HadisTransmitter connections for {total_hadis} Hadiths."))
self.stdout.write(self.style.SUCCESS(f"Done! Created {created_links_count} connections."))

2
apps/hadis/views/hadis.py

@ -369,7 +369,7 @@ class HadisTransmittersView(RetrieveAPIView):
serializer_class = HadisTransmitterListSerializer
lookup_field = 'slug'
lookup_url_kwarg = 'hadis_slug'
pagination_class = NoPagination
@hadis_transmitters_swagger
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)

Loading…
Cancel
Save