2 changed files with 62 additions and 62 deletions
@ -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.")) |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue