9 changed files with 215 additions and 24 deletions
-
9apps/hadis/admin/transmitter.py
-
91apps/hadis/management/commands/seed_hadis_transmitter.py
-
14apps/hadis/management/commands/seed_transmitters.py
-
26apps/hadis/migrations/0081_alter_hadistransmitter_status.py
-
16apps/hadis/migrations/0082_remove_hadistransmitter_status.py
-
15apps/hadis/migrations/0083_auto_20251224_1214.py
-
26apps/hadis/migrations/0084_hadistransmitter_status.py
-
15apps/hadis/models/transmitter.py
-
17apps/hadis/serializers/hadis.py
@ -0,0 +1,91 @@ |
|||||
|
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 |
||||
|
from apps.hadis.models import Hadis, Transmitters, NarratorLayer, HadisTransmitter |
||||
|
|
||||
|
class Command(BaseCommand): |
||||
|
help = 'Seeds HadisTransmitter instances with specific constraints' |
||||
|
|
||||
|
def handle(self, *args, **options): |
||||
|
self.stdout.write("Starting HadisTransmitter seeding...") |
||||
|
|
||||
|
# --------------------------------------------------------- |
||||
|
# 1. Fetch the specific Objects |
||||
|
# --------------------------------------------------------- |
||||
|
layers = list(NarratorLayer.objects.filter(id__range=(11, 15))) |
||||
|
transmitters = list(Transmitters.objects.filter(id__range=(84, 91))) |
||||
|
|
||||
|
# Hadis query |
||||
|
hadis_qs = Hadis.objects.filter( |
||||
|
Q(id__range=(1800, 1852)) | Q(id__range=(1877, 1889)) |
||||
|
) |
||||
|
|
||||
|
# --------------------------------------------------------- |
||||
|
# 2. Validation |
||||
|
# --------------------------------------------------------- |
||||
|
if len(layers) < 2: |
||||
|
self.stdout.write(self.style.ERROR(f"Need at least 2 NarratorLayers to satisfy constraints, but found {len(layers)}.")) |
||||
|
return |
||||
|
if not transmitters: |
||||
|
self.stdout.write(self.style.ERROR("No Transmitters found in range 84-91.")) |
||||
|
return |
||||
|
if not hadis_qs.exists(): |
||||
|
self.stdout.write(self.style.ERROR("No Hadis found in the specified ranges.")) |
||||
|
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_count = 0 |
||||
|
|
||||
|
self.stdout.write("Beginning processing...") |
||||
|
|
||||
|
for i, hadis in enumerate(hadis_qs, 1): |
||||
|
# Print progress every 5 items so you know it's not frozen |
||||
|
if i % 5 == 0: |
||||
|
self.stdout.write(f"Processing {i}/{total_hadis} (Hadis ID: {hadis.id})...") |
||||
|
|
||||
|
# Wrap PER ITEM in transaction to avoid long db locks |
||||
|
with transaction.atomic(): |
||||
|
# CONSTRAINT 1: Each hadis must have 3-4 transmitters |
||||
|
chain_length = random.randint(3, 4) |
||||
|
|
||||
|
if len(transmitters) < chain_length: |
||||
|
self.stdout.write(self.style.WARNING(f"Not enough transmitters. Skipping Hadis {hadis.id}.")) |
||||
|
continue |
||||
|
|
||||
|
# Pick unique transmitters |
||||
|
selected_transmitters = random.sample(transmitters, chain_length) |
||||
|
|
||||
|
# CONSTRAINT 2: Transmitters must be separated to at least 2 narrator layers |
||||
|
# LOGIC FIX: Instead of a while loop, we force the condition explicitly. |
||||
|
|
||||
|
# Step A: Pick 2 DISTINCT layers guaranteed |
||||
|
guaranteed_layers = random.sample(layers, 2) |
||||
|
|
||||
|
# Step B: Fill the remaining slots (1 or 2 slots) with random layers |
||||
|
remaining_slots = chain_length - 2 |
||||
|
other_layers = [random.choice(layers) for _ in range(remaining_slots)] |
||||
|
|
||||
|
# Step C: Combine and Shuffle so the distinct ones aren't always first |
||||
|
final_layers = guaranteed_layers + other_layers |
||||
|
random.shuffle(final_layers) |
||||
|
|
||||
|
# Create the connections |
||||
|
for index, transmitter in enumerate(selected_transmitters): |
||||
|
HadisTransmitter.objects.create( |
||||
|
hadis=hadis, |
||||
|
transmitter=transmitter, |
||||
|
narrator_layer=final_layers[index], |
||||
|
order=index, |
||||
|
status=transmitter.reliability if hasattr(transmitter, 'reliability') else None |
||||
|
) |
||||
|
created_count += 1 |
||||
|
|
||||
|
self.stdout.write(self.style.SUCCESS(f"Done! Successfully created {created_count} HadisTransmitter instances.")) |
||||
@ -0,0 +1,26 @@ |
|||||
|
# Generated by Django 4.2.27 on 2025-12-24 11:58 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
dependencies = [ |
||||
|
("hadis", "0080_transmitteropinion_status"), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name="hadistransmitter", |
||||
|
name="status", |
||||
|
field=models.ForeignKey( |
||||
|
blank=True, |
||||
|
help_text="Reliability status of the narrator", |
||||
|
null=True, |
||||
|
on_delete=django.db.models.deletion.SET_NULL, |
||||
|
related_name="hadis_transmitters", |
||||
|
to="hadis.transmitterreliability", |
||||
|
verbose_name="reliability status", |
||||
|
), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,16 @@ |
|||||
|
# Generated by Django 4.2.27 on 2025-12-24 12:11 |
||||
|
|
||||
|
from django.db import migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
dependencies = [ |
||||
|
("hadis", "0081_alter_hadistransmitter_status"), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.RemoveField( |
||||
|
model_name="hadistransmitter", |
||||
|
name="status", |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,15 @@ |
|||||
|
from django.db import migrations |
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('hadis', '0082_remove_hadistransmitter_status'), # Keep your actual dependency here |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
# This tells Django: "Run this SQL command, but don't try to update your internal model state" |
||||
|
migrations.RunSQL( |
||||
|
sql="ALTER TABLE hadis_hadistransmitter DROP COLUMN status;", |
||||
|
reverse_sql="ALTER TABLE hadis_hadistransmitter ADD COLUMN status varchar(255);" # Optional fallback |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,26 @@ |
|||||
|
# Generated by Django 4.2.27 on 2025-12-24 12:32 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
dependencies = [ |
||||
|
("hadis", "0083_auto_20251224_1214"), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name="hadistransmitter", |
||||
|
name="status", |
||||
|
field=models.ForeignKey( |
||||
|
blank=True, |
||||
|
help_text="Reliability status of the narrator", |
||||
|
null=True, |
||||
|
on_delete=django.db.models.deletion.SET_NULL, |
||||
|
related_name="hadis_transmitters", |
||||
|
to="hadis.transmitterreliability", |
||||
|
verbose_name="reliability status", |
||||
|
), |
||||
|
), |
||||
|
] |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue