Browse Source

hadistransmitter status has chainged

master
Mohsen Taba 5 months ago
parent
commit
133f25918e
  1. 9
      apps/hadis/admin/transmitter.py
  2. 91
      apps/hadis/management/commands/seed_hadis_transmitter.py
  3. 24
      apps/hadis/management/commands/seed_transmitters.py
  4. 26
      apps/hadis/migrations/0081_alter_hadistransmitter_status.py
  5. 16
      apps/hadis/migrations/0082_remove_hadistransmitter_status.py
  6. 15
      apps/hadis/migrations/0083_auto_20251224_1214.py
  7. 26
      apps/hadis/migrations/0084_hadistransmitter_status.py
  8. 15
      apps/hadis/models/transmitter.py
  9. 17
      apps/hadis/serializers/hadis.py

9
apps/hadis/admin/transmitter.py

@ -11,7 +11,7 @@ class HadisTransmitterInline(TabularInline):
"""Inline for HadisTransmitter in Transmitters admin"""
model = HadisTransmitter
extra = 0
fields = ('hadis', 'order', 'status')
fields = ('hadis', 'order')
readonly_fields = ('created_at',)
@ -51,8 +51,8 @@ class TransmittersAdmin(ModelAdmin):
class HadisTransmitterAdmin(ModelAdmin):
"""Admin for HadisTransmitter model"""
list_display = ('hadis', 'transmitter', 'order', 'status', 'created_at')
list_filter = ('status', 'created_at')
list_display = ('hadis', 'transmitter', 'order', 'created_at')
list_filter = ( 'created_at',)
search_fields = ('hadis__title', 'transmitter__full_name')
readonly_fields = ('created_at',)
ordering = ('hadis', 'order')
@ -61,9 +61,6 @@ class HadisTransmitterAdmin(ModelAdmin):
(None, {
'fields': ('hadis', 'transmitter', 'order')
}),
(_('Status Information'), {
'fields': ('status',)
}),
(_('Timestamps'), {
'fields': ('created_at',),
'classes': ('collapse',)

91
apps/hadis/management/commands/seed_hadis_transmitter.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."))

24
apps/hadis/management/commands/seed_transmitters.py

@ -3,12 +3,13 @@ from django.core.management.base import BaseCommand
from django.core.exceptions import ObjectDoesNotExist
# Ensure these imports match your actual app structure
from apps.hadis.models import (
NarratorLayer,
Transmitters,
HadisTransmitter,
TransmitterOpinion,
TransmitterOriginalText,
Hadis
NarratorLayer,
Transmitters,
HadisTransmitter,
TransmitterOpinion,
TransmitterOriginalText,
Hadis,
TransmitterReliability
)
class Command(BaseCommand):
@ -246,12 +247,21 @@ class Command(BaseCommand):
for index, narrator in enumerate(chain_narrators):
layer_obj = NarratorLayer.objects.get(number=5-index) if index < 5 else None
# Get or create reliable status
reliable_status, created = TransmitterReliability.objects.get_or_create(
slug='reliable',
defaults={
'title': self.create_json_field('Reliable', 'موثوق', 'Надежный'),
'color': 'green'
}
)
HadisTransmitter.objects.create(
hadis=hadis_obj,
transmitter=narrator,
narrator_layer=layer_obj,
order=index + 1,
status=HadisTransmitter.ReliabilityStatus.RELIABLE,
status=reliable_status,
is_gap=False
)

26
apps/hadis/migrations/0081_alter_hadistransmitter_status.py

@ -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",
),
),
]

16
apps/hadis/migrations/0082_remove_hadistransmitter_status.py

@ -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",
),
]

15
apps/hadis/migrations/0083_auto_20251224_1214.py

@ -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
),
]

26
apps/hadis/migrations/0084_hadistransmitter_status.py

@ -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",
),
),
]

15
apps/hadis/models/transmitter.py

@ -273,11 +273,6 @@ class Transmitters(models.Model):
class HadisTransmitter(models.Model):
class ReliabilityStatus(models.TextChoices):
RELIABLE = 'reliable', _('Reliable')
WEAK = 'weak', _('Weak')
UNKNOWN = 'unknown', _('Unknown')
hadis = models.ForeignKey(
"hadis.Hadis",
on_delete=models.CASCADE,
@ -299,11 +294,13 @@ class HadisTransmitter(models.Model):
blank=True,
help_text=_('The layer/class (Tabaqah) this narrator belongs to')
)
status = models.CharField(
max_length=20,
choices=ReliabilityStatus.choices,
default=ReliabilityStatus.UNKNOWN,
status = models.ForeignKey(
TransmitterReliability,
on_delete=models.SET_NULL,
verbose_name=_('reliability status'),
related_name='hadis_transmitters',
null=True,
blank=True,
help_text=_('Reliability status of the narrator')
)
order = models.PositiveIntegerField(

17
apps/hadis/serializers/hadis.py

@ -447,10 +447,11 @@ class HadisTransmitterSerializer(serializers.ModelSerializer):
transmitter = TransmitterShortSerializer(read_only=True)
narrator_layer_description = serializers.SerializerMethodField()
layer = serializers.SerializerMethodField()
status = serializers.SerializerMethodField()
class Meta:
model = HadisTransmitter
fields = [
'id', 'order', 'is_gap','narrator_layer_description','layer', 'transmitter'
'id', 'order', 'is_gap','narrator_layer_description','layer', 'transmitter', 'status'
]
def get_narrator_layer_description(self, obj):
@ -462,7 +463,19 @@ class HadisTransmitterSerializer(serializers.ModelSerializer):
def get_layer(self, obj):
"""Get narrator layer slug"""
return obj.narrator_layer.slug
return obj.narrator_layer.slug if obj.narrator_layer else None
def get_status(self, obj):
"""Serialize the status foreign key"""
if obj.status:
request = self.context.get('request')
return {
'id': obj.status.id,
'title': get_localized_text(obj.status.title, request),
'slug': obj.status.slug,
'color': obj.status.color
}
return None
# serializers.py

Loading…
Cancel
Save