Browse Source

narrators slug added

master
Mohsen Taba 5 months ago
parent
commit
7dbe9b355d
  1. 24
      apps/hadis/docs.py
  2. 71
      apps/hadis/management/commands/generate_transmit_slug.py
  3. 19
      apps/hadis/migrations/0046_transmitters_slug.py
  4. 16
      apps/hadis/migrations/0047_remove_transmitters_slug.py
  5. 19
      apps/hadis/migrations/0048_transmitters_slug.py
  6. 19
      apps/hadis/migrations/0049_alter_transmitters_slug.py
  7. 12
      apps/hadis/models/transmitter.py
  8. 2
      apps/hadis/serializers/hadis.py
  9. 6
      apps/hadis/urls.py
  10. 33
      apps/hadis/views/transmitter.py

24
apps/hadis/docs.py

@ -779,6 +779,7 @@ transmitter_list_swagger = swagger_auto_schema(
{
"id": 56,
"full_name": "Абу Дауд ас-Сиджистани",
"slug": "abdullah-ibn-abbas",
"birth_year_hijri": 202,
"death_year_hijri": 275,
"known_as": "Imam Abu Daud",
@ -790,6 +791,7 @@ transmitter_list_swagger = swagger_auto_schema(
{
"id": 51,
"full_name": "Мухаммад ибн Якуб Кулейни",
"slug": "abdullah-ibn-abbas",
"birth_year_hijri": 250,
"death_year_hijri": 329,
"known_as": "Thiqat al-Islam",
@ -816,10 +818,10 @@ transmitter_detail_swagger = swagger_auto_schema(
tags=['Hadis'],
manual_parameters=[
openapi.Parameter(
'transmitters_id',
'narrator_slug',
openapi.IN_PATH,
description="ID of the transmitter",
type=openapi.TYPE_INTEGER,
description="Slug of narrator",
type=openapi.TYPE_STRING,
required=True
)
],
@ -1001,12 +1003,12 @@ transmitter_opinion_swagger = swagger_auto_schema(
tags=['Hadis'],
manual_parameters=[
openapi.Parameter(
'transmitters_id',
'narrator_slug',
openapi.IN_PATH,
description="Unique identifier of the transmitter (narrator). Must be a valid transmitter ID that exists in the system.",
type=openapi.TYPE_INTEGER,
description="Narrator's slug",
type=openapi.TYPE_STRING,
required=True,
example=56
example="abdullah-ibn-abbas"
)
],
responses={
@ -1084,12 +1086,12 @@ transmitter_original_text_swagger = swagger_auto_schema(
tags=['Hadis'],
manual_parameters=[
openapi.Parameter(
'transmitters_id',
'narrator_slug',
openapi.IN_PATH,
description="Unique identifier of the transmitter (narrator). Must be a valid transmitter ID that exists in the system.",
type=openapi.TYPE_INTEGER,
description="Narrator's slug",
type=openapi.TYPE_STRING,
required=True,
example=56
example="abdullah-ibn-abbas"
)
],
responses={

71
apps/hadis/management/commands/generate_transmit_slug.py

@ -0,0 +1,71 @@
# Create this file: yourapp/management/commands/generate_transmitter_slugs.py
from django.core.management.base import BaseCommand
from django.utils.text import slugify
from apps.hadis.models import Transmitters # adjust import path as needed
class Command(BaseCommand):
help = 'Generate unique slugs for all transmitters'
def add_arguments(self, parser):
parser.add_argument(
'--regenerate',
action='store_true',
help='Regenerate slugs even if they already exist',
)
def handle(self, *args, **options):
regenerate = options['regenerate']
transmitters = Transmitters.objects.all()
updated_count = 0
skipped_count = 0
self.stdout.write(
self.style.SUCCESS(f'\n📝 Processing {transmitters.count()} transmitters...\n')
)
for transmitter in transmitters:
# Skip if slug exists and regenerate is False
if transmitter.slug and not regenerate:
self.stdout.write(
self.style.WARNING(f"⊘ Skipped: {transmitter.full_name} (slug exists)")
)
skipped_count += 1
continue
# Generate base slug from full_name
base_slug = slugify(transmitter.full_name, allow_unicode=True)
if not base_slug:
self.stdout.write(
self.style.ERROR(f"✗ Error: {transmitter.full_name} - Cannot generate slug from empty name")
)
continue
# Ensure uniqueness
slug = base_slug
counter = 1
while Transmitters.objects.filter(slug=slug).exclude(pk=transmitter.pk).exists():
slug = f"{base_slug}-{counter}"
counter += 1
# Update the transmitter
transmitter.slug = slug
transmitter.save()
updated_count += 1
self.stdout.write(
self.style.SUCCESS(f"✓ Generated: {transmitter.full_name} → {slug}")
)
# Print summary
self.stdout.write("\n" + "="*70)
self.stdout.write(self.style.SUCCESS("SLUG GENERATION SUMMARY"))
self.stdout.write("="*70)
self.stdout.write(f"✓ Generated: {updated_count}")
self.stdout.write(f"⊘ Skipped: {skipped_count}")
self.stdout.write(f"📊 Total: {transmitters.count()}")
self.stdout.write("="*70 + "\n")

19
apps/hadis/migrations/0046_transmitters_slug.py

@ -0,0 +1,19 @@
# Generated by Django 5.2.9 on 2025-12-17 13:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("hadis", "0045_bookreference_publisher"),
]
operations = [
migrations.AddField(
model_name="transmitters",
name="slug",
field=models.SlugField(
blank=True, max_length=255, unique=True, verbose_name="slug"
),
),
]

16
apps/hadis/migrations/0047_remove_transmitters_slug.py

@ -0,0 +1,16 @@
# Generated by Django 5.2.9 on 2025-12-17 13:26
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("hadis", "0046_transmitters_slug"),
]
operations = [
migrations.RemoveField(
model_name="transmitters",
name="slug",
),
]

19
apps/hadis/migrations/0048_transmitters_slug.py

@ -0,0 +1,19 @@
# Generated by Django 5.2.9 on 2025-12-17 13:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("hadis", "0047_remove_transmitters_slug"),
]
operations = [
migrations.AddField(
model_name="transmitters",
name="slug",
field=models.SlugField(
blank=True, max_length=255, null=True, verbose_name="slug"
),
),
]

19
apps/hadis/migrations/0049_alter_transmitters_slug.py

@ -0,0 +1,19 @@
# Generated by Django 5.2.9 on 2025-12-17 13:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("hadis", "0048_transmitters_slug"),
]
operations = [
migrations.AlterField(
model_name="transmitters",
name="slug",
field=models.SlugField(
blank=True, max_length=255, unique=True, verbose_name="slug"
),
),
]

12
apps/hadis/models/transmitter.py

@ -59,6 +59,7 @@ class Transmitters(models.Model):
kunya = models.CharField(max_length=255, verbose_name=_('Kunya'), blank=True, null=True, help_text=_('e.g., Abu Abdullah'))
known_as = models.CharField(max_length=255, verbose_name=_('Known As'), blank=True, null=True)
nickname = models.CharField(max_length=255, verbose_name=_('Nickname/Laqab'), blank=True, null=True)
slug = models.SlugField(max_length=255, verbose_name=_('slug'), blank=True,unique=True)
# Geographic Information
origin = models.CharField(max_length=255, verbose_name=_('Origin'), blank=True, null=True, help_text=_('Place of origin'))
@ -114,6 +115,17 @@ class Transmitters(models.Model):
verbose_name_plural = _('Transmitters')
ordering = ('full_name',)
def save(self, *args, **kwargs):
if not self.slug:
base_slug = slugify(self.full_name, allow_unicode=True)
slug = base_slug
counter = 1
while Transmitters.objects.filter(slug=slug).exclude(pk=self.pk).exists():
slug = f"{base_slug}-{counter}"
counter += 1
self.slug = slug
super().save(*args, **kwargs)
def __str__(self):
return self.full_name

2
apps/hadis/serializers/hadis.py

@ -196,7 +196,7 @@ class TransmitterSerializer(serializers.ModelSerializer):
class Meta:
model = Transmitters
fields = [
'id', 'full_name', 'birth_year_hijri', 'death_year_hijri',
'id', 'full_name', 'slug','birth_year_hijri', 'death_year_hijri',
"known_as",'nickname','reliability','madhhab','generation'
]

6
apps/hadis/urls.py

@ -25,9 +25,9 @@ urlpatterns = [
path('categories/<str:sect_type>/', CategoriesBySectView.as_view(), name='categories-by-sect'),
path('categories/', CategoriesView.as_view(), name='categories'),
path('narrators/',TransmitterView.as_view(), name='narrators'),
path('narrators/<int:transmitters_id>',TransmitterDetailView.as_view(), name='narrator-detail'),
path('narrators/<int:transmitters_id>/opinions',TransmitterOpinionView.as_view(), name='narrator-opinions'),
path('narrators/<int:transmitters_id>/original_texts',TransmitterOriginalTextView.as_view(), name='narrator-original-texts'),
path('narrators/<str:narrator_slug>',TransmitterDetailView.as_view(), name='narrator-detail'),
path('narrators/<str:narrator_slug>/opinions',TransmitterOpinionView.as_view(), name='narrator-opinions'),
path('narrators/<str:narrator_slug>/original_texts',TransmitterOriginalTextView.as_view(), name='narrator-original-texts'),
path('references/',BookReferencesView.as_view(), name='references'),
path('references/<str:reference_slug>',BookDetailView.as_view(), name='reference-detail'),
path('references/attributes/',BookAttributeView.as_view(), name='book-attributes'),

33
apps/hadis/views/transmitter.py

@ -39,16 +39,16 @@ class TransmitterView(ListAPIView):
class TransmitterDetailView(RetrieveAPIView):
serializer_class = TransmitterDetailSerializer
lookup_field = 'id'
lookup_url_kwarg = 'transmitters_id'
lookup_field = 'slug'
lookup_url_kwarg = 'narrator_slug'
@transmitter_detail_swagger
def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)
def get_queryset(self):
input = self.kwargs['transmitters_id']
return Transmitters.objects.filter(id=input)
input = self.kwargs.get('narrator_slug')
return Transmitters.objects.filter(slug=input)
class TransmitterOpinionView(ListAPIView):
serializer_class = TransmitterOpinionSerializer
@ -58,8 +58,16 @@ class TransmitterOpinionView(ListAPIView):
return self.list(request, *args, **kwargs)
def get_queryset(self):
transmitter_id = self.kwargs['transmitters_id']
return TransmitterOpinion.objects.filter(transmitter_id=transmitter_id)
narrator_slug = self.kwargs.get('narrator_slug')
return TransmitterOpinion.objects.filter(
transmitter__slug=narrator_slug
).select_related(
'transmitter' # Essential if serializer includes transmitter data
).prefetch_related(
# Add any nested relations from TransmitterOriginalTextSerializer
# 'translations',
# 'manuscript_references',
)
class TransmitterOriginalTextView(ListAPIView):
@ -70,8 +78,17 @@ class TransmitterOriginalTextView(ListAPIView):
return self.list(request, *args, **kwargs)
def get_queryset(self):
transmitter_id = self.kwargs['transmitters_id']
return TransmitterOriginalText.objects.filter(transmitter_id=transmitter_id)
narrator_slug = self.kwargs.get('narrator_slug')
return TransmitterOriginalText.objects.filter(
transmitter__slug=narrator_slug
).select_related(
'transmitter' # Essential if serializer includes transmitter data
).prefetch_related(
# Add any nested relations from TransmitterOriginalTextSerializer
# 'translations',
# 'manuscript_references',
)
class TransmitterSyncView(ListAPIView):

Loading…
Cancel
Save