2 changed files with 62 additions and 62 deletions
@ -1,93 +1,93 @@ |
|||||
import random |
import random |
||||
import time |
|
||||
from django.core.management.base import BaseCommand |
from django.core.management.base import BaseCommand |
||||
from django.db import transaction |
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 |
from apps.hadis.models import Hadis, Transmitters, NarratorLayer, HadisTransmitter |
||||
|
|
||||
class Command(BaseCommand): |
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): |
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()) |
layers = list(NarratorLayer.objects.all()) |
||||
transmitters = list(Transmitters.objects.all()) |
transmitters = list(Transmitters.objects.all()) |
||||
# Fetch all Hadis records |
|
||||
hadis_qs = Hadis.objects.all() |
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 |
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 |
return |
||||
|
|
||||
if not hadis_qs.exists(): |
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 |
return |
||||
|
|
||||
total_hadis = hadis_qs.count() |
total_hadis = hadis_qs.count() |
||||
self.stdout.write(f"Found {len(layers)} Layers, {len(transmitters)} Transmitters, and {total_hadis} Hadis.") |
|
||||
|
self.stdout.write(f"Found {len(layers)} Layers, {len(transmitters)} Transmitters. Processing {total_hadis} Hadiths...") |
||||
|
|
||||
# --------------------------------------------------------- |
|
||||
# 3. Creation Loop |
|
||||
# --------------------------------------------------------- |
|
||||
|
# 3. Processing |
||||
created_links_count = 0 |
created_links_count = 0 |
||||
|
|
||||
self.stdout.write("Beginning processing...") |
|
||||
|
|
||||
for i, hadis in enumerate(hadis_qs, 1): |
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}...") |
self.stdout.write(f"Processing {i}/{total_hadis}...") |
||||
|
|
||||
with transaction.atomic(): |
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() |
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) |
|
||||
|
|
||||
# CONSTRAINT 2: Must have at least 2-3 narrator layers |
|
||||
target_unique_layers = random.randint(2, 3) |
|
||||
|
|
||||
# --- Logic to Select Transmitters and Layers --- |
|
||||
|
|
||||
# A. Select Transmitters |
|
||||
selected_transmitters = random.sample(transmitters, chain_length) |
|
||||
|
|
||||
# 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) |
|
||||
|
|
||||
# --- 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 |
|
||||
|
|
||||
self.stdout.write(self.style.SUCCESS(f"Done! Created {created_links_count} HadisTransmitter connections for {total_hadis} Hadiths.")) |
|
||||
|
# 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: 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) |
||||
|
|
||||
|
# 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 |
||||
|
|
||||
|
# 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 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} connections.")) |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue