From a2ea302d5dbf53538b393a47a3b3e44c96648f40 Mon Sep 17 00:00:00 2001 From: mohsentaba Date: Tue, 7 Jul 2026 16:18:58 +0330 Subject: [PATCH] refrence researchers and author fixed --- apps/hadis/admin/reference.py | 14 ++-- .../commands/seed_edition_researchers.py | 81 +++++++++++++++++++ ...ove_bookauthor_book_references_and_more.py | 51 ++++++++++++ apps/hadis/models/reference.py | 52 ++++++++++-- apps/hadis/serializers/hadis.py | 7 +- apps/hadis/serializers/reference_v2.py | 35 ++++++-- apps/hadis/serializers/serializers_admin.py | 60 +++++++++++--- apps/hadis/views/hadis.py | 21 +++-- apps/hadis/views/reference_v2.py | 31 +++---- apps/hadis/views/transmitter.py | 4 +- apps/hadis/views_admin.py | 5 +- 11 files changed, 295 insertions(+), 66 deletions(-) create mode 100644 apps/hadis/management/commands/seed_edition_researchers.py create mode 100644 apps/hadis/migrations/0030_remove_bookauthor_book_references_and_more.py diff --git a/apps/hadis/admin/reference.py b/apps/hadis/admin/reference.py index 1fd2834..fadc960 100644 --- a/apps/hadis/admin/reference.py +++ b/apps/hadis/admin/reference.py @@ -491,7 +491,7 @@ class BookReferenceAdmin(ModelAdmin): fieldsets = ( (_('Basic Info'), { - 'fields': ('title', 'description', 'slug', 'language', 'tags', 'type') + 'fields': ('title', 'description', 'slug', 'language', 'tags', 'type', 'author') }), (_('Publication Info'), { 'fields': ('number_page',) @@ -516,6 +516,12 @@ class BookReferenceAdmin(ModelAdmin): return '-' +class BookAuthorAdminForm(forms.ModelForm): + class Meta: + model = BookAuthor + fields = '__all__' + + class BookAuthorAdmin(ModelAdmin): """Admin for BookAuthor model""" form = BookAuthorAdminForm @@ -525,9 +531,6 @@ class BookAuthorAdmin(ModelAdmin): readonly_fields = ('created_at', 'updated_at') list_filter = ('birth_year_hijri', 'death_year_hijri', 'birth_year_miladi', 'death_year_miladi', 'created_at') - # Use filter_horizontal for ManyToMany fields to make selection easier - filter_horizontal = ('book_references',) - fieldsets = ( (_('Basic Info'), { 'fields': ('name',) @@ -538,9 +541,6 @@ class BookAuthorAdmin(ModelAdmin): (_('Dates (Miladi)'), { 'fields': ('birth_year_miladi', 'death_year_miladi') }), - (_('References'), { - 'fields': ('book_references',) - }), (_('Timestamps'), { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) diff --git a/apps/hadis/management/commands/seed_edition_researchers.py b/apps/hadis/management/commands/seed_edition_researchers.py new file mode 100644 index 0000000..6741359 --- /dev/null +++ b/apps/hadis/management/commands/seed_edition_researchers.py @@ -0,0 +1,81 @@ +# backend/apps/hadis/management/commands/seed_edition_researchers.py + +import random +from django.core.management.base import BaseCommand +from django.db import transaction +from django.utils.text import slugify +from apps.hadis.models import BookEdition, BookAuthor, BookResearcher + +class Command(BaseCommand): + help = 'Assigns two researchers to each BookEdition: one random text-only, one linked to a random existing BookAuthor.' + + def handle(self, *args, **options): + self.stdout.write(self.style.WARNING("Starting to seed edition researchers...")) + + editions = list(BookEdition.objects.all()) + authors = list(BookAuthor.objects.all()) + + if not editions: + self.stdout.write(self.style.ERROR("No BookEditions found in the database.")) + return + + if not authors: + self.stdout.write(self.style.ERROR("No BookAuthors found. Please add some authors first.")) + return + + # 1. Clean existing researchers + self.stdout.write("Deleting existing BookResearchers...") + BookResearcher.objects.all().delete() + + random_researcher_names = [ + {"fa": "دکتر سید علی موسوی", "en": "Dr. Seyed Ali Mousavi"}, + {"fa": "استاد محمد کریمی", "en": "Professor Mohammad Karimi"}, + {"fa": "دکتر رضا علوی", "en": "Dr. Reza Alavi"}, + {"fa": "پژوهشگر حمید احمدی", "en": "Researcher Hamid Ahmadi"}, + {"fa": "دکتر مریم رضایی", "en": "Dr. Maryam Rezaei"}, + {"fa": "استاد فاطمه حسینی", "en": "Professor Fatemeh Hosseini"}, + {"fa": "دکتر جعفر صادقی", "en": "Dr. Jafar Sadeghi"}, + ] + + text_only_count = 0 + linked_author_count = 0 + + with transaction.atomic(): + for edition in editions: + # 1. First researcher: Text-only (Random Name & Slug) + name_data = random.choice(random_researcher_names) + name_field = [ + {"language_code": "fa", "text": name_data["fa"]}, + {"language_code": "en", "text": name_data["en"]}, + ] + # Ensure clean slug + base_slug = slugify(name_data["en"]) + slug_val = base_slug + counter = 1 + while BookResearcher.objects.filter(slug=slug_val).exists(): + slug_val = f"{base_slug}-{counter}" + counter += 1 + + BookResearcher.objects.create( + book_edition=edition, + name=name_field, + slug=slug_val, + author=None + ) + text_only_count += 1 + + # 2. Second researcher: Linked to a random BookAuthor + random_author = random.choice(authors) + BookResearcher.objects.create( + book_edition=edition, + author=random_author + ) + linked_author_count += 1 + + self.stdout.write( + self.style.SUCCESS( + f"Successfully seeded researchers for {len(editions)} BookEditions!\n" + f"- Created {text_only_count} text-only researchers.\n" + f"- Created {linked_author_count} researchers linked to existing authors." + ) + ) diff --git a/apps/hadis/migrations/0030_remove_bookauthor_book_references_and_more.py b/apps/hadis/migrations/0030_remove_bookauthor_book_references_and_more.py new file mode 100644 index 0000000..15bc8f4 --- /dev/null +++ b/apps/hadis/migrations/0030_remove_bookauthor_book_references_and_more.py @@ -0,0 +1,51 @@ +# Generated by Django 5.2.12 on 2026-07-07 16:02 + +import django.db.models.deletion +from django.db import migrations, models + +def copy_m2m_to_fk(apps, schema_editor): + BookReference = apps.get_model('hadis', 'BookReference') + for book in BookReference.objects.all(): + # Get first author from many-to-many relationship + # The relationship is still accessible as 'authors' on BookReference in this state + first_author = book.authors.first() if hasattr(book, 'authors') else None + if first_author: + book.author = first_author + book.save() + +class Migration(migrations.Migration): + + dependencies = [ + ('hadis', '0029_booktype_sect'), + ] + + operations = [ + migrations.AddField( + model_name='bookreference', + name='author', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='book_references', to='hadis.bookauthor', verbose_name='Author'), + ), + migrations.RunPython(copy_m2m_to_fk, reverse_code=migrations.RunPython.noop), + migrations.RemoveField( + model_name='bookauthor', + name='book_references', + ), + migrations.RemoveField( + model_name='bookreference', + name='researcher', + ), + migrations.CreateModel( + name='BookResearcher', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.JSONField(blank=True, default=list, verbose_name='Name')), + ('slug', models.SlugField(blank=True, max_length=255, null=True, verbose_name='slug')), + ('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='researcher_profiles', to='hadis.bookauthor', verbose_name='Author')), + ('book_edition', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='researchers', to='hadis.bookedition', verbose_name='Book Edition')), + ], + options={ + 'verbose_name': 'Book Researcher', + 'verbose_name_plural': 'Book Researchers', + }, + ), + ] diff --git a/apps/hadis/models/reference.py b/apps/hadis/models/reference.py index d9b037d..f151b79 100644 --- a/apps/hadis/models/reference.py +++ b/apps/hadis/models/reference.py @@ -106,8 +106,15 @@ class BookReference(models.Model): related_name='book_references' ) type = models.ForeignKey('BookType', on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Type')) + author = models.ForeignKey( + 'BookAuthor', + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name='book_references', + verbose_name=_('Author') + ) order = models.IntegerField(default=0, verbose_name=_('Order')) - researcher = models.JSONField(default=list, blank=True, verbose_name=_('Researcher')) rate = models.DecimalField( max_digits=3, decimal_places=2, @@ -388,12 +395,7 @@ class BookAuthor(models.Model): birth_year_miladi = models.IntegerField(verbose_name=_("Birth Year (Miladi)"), null=True, blank=True) death_year_miladi = models.IntegerField(verbose_name=_("Death Year (Miladi)"), null=True, blank=True) - book_references = models.ManyToManyField( - BookReference, - related_name='authors', - verbose_name=_('book references'), - blank=True - ) + created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at')) updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at')) @@ -451,6 +453,7 @@ class BookAuthor(models.Model): import time self.slug = f"author-{int(time.time() * 1000) % 1000000}" super().save(*args, **kwargs) + self.researcher_profiles.all().update(name=self.name, slug=self.slug) class BookAttribute(models.Model): @@ -513,3 +516,38 @@ class BookAttribute(models.Model): if isinstance(tr, dict) and tr.get('language_code') == 'en': return tr.get('text', '') return None + + +class BookResearcher(models.Model): + book_edition = models.ForeignKey( + 'BookEdition', + on_delete=models.CASCADE, + related_name='researchers', + verbose_name=_('Book Edition') + ) + author = models.ForeignKey( + 'BookAuthor', + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name='researcher_profiles', + verbose_name=_('Author') + ) + name = models.JSONField(default=list, blank=True, verbose_name=_('Name')) + slug = models.SlugField(max_length=255, verbose_name=_('slug'), null=True, blank=True) + + class Meta: + verbose_name = _('Book Researcher') + verbose_name_plural = _('Book Researchers') + + def save(self, *args, **kwargs): + if self.author: + self.name = self.author.name + self.slug = self.author.slug + super().save(*args, **kwargs) + + def __str__(self): + try: + return self.name[0]['text'] + except: + return self.slug or f"Researcher {self.id}" diff --git a/apps/hadis/serializers/hadis.py b/apps/hadis/serializers/hadis.py index b7d4d73..ec469ca 100644 --- a/apps/hadis/serializers/hadis.py +++ b/apps/hadis/serializers/hadis.py @@ -127,7 +127,7 @@ class HadisSyncSerializer(serializers.ModelSerializer): for reference in obj.references.all(): book = reference.book_reference - authors = book.authors.all() if book else [] + authors = [book.author] if book and book.author else [] references_block.append({ 'id': reference.id, 'title': get_localized_text(book.title, request) if book else None, @@ -833,7 +833,7 @@ class HadisReferenceSerializer(serializers.ModelSerializer): """Get list of localized author names""" try: # 1. Fetch the BookAuthor objects - authors = obj.book_reference.authors.all() + authors = [obj.book_reference.author] if obj.book_reference and obj.book_reference.author else [] if not authors: return [] @@ -1111,9 +1111,10 @@ class BaseDetailedReferenceSerializer(serializers.ModelSerializer): def get_book_authors(self, obj): if obj.book_reference: request = self.context.get('request') + authors = [obj.book_reference.author] if obj.book_reference.author else [] return [ {"id": author.id, "name": get_localized_text(author.name, request)} - for author in obj.book_reference.authors.all() + for author in authors ] return [] diff --git a/apps/hadis/serializers/reference_v2.py b/apps/hadis/serializers/reference_v2.py index 2f060b9..4348298 100644 --- a/apps/hadis/serializers/reference_v2.py +++ b/apps/hadis/serializers/reference_v2.py @@ -1,6 +1,6 @@ from rest_framework import serializers from rest_framework.pagination import PageNumberPagination -from ..models import BookReference, BookAuthor, BookEdition, BookVolume, BookTag +from ..models import BookReference, BookAuthor, BookEdition, BookVolume, BookTag, BookResearcher from .category import get_localized_text from apps.hadis.serializers import HadisListSerializer, HadisShortSerializer from ..serializers.category import LocalizedField @@ -18,9 +18,15 @@ class BookAuthorV2Serializer(serializers.ModelSerializer): model = BookAuthor fields = ['id', 'name', 'slug'] +class BookResearcherV2Serializer(serializers.ModelSerializer): + name = LocalizedField() + class Meta: + model = BookResearcher + fields = ['id', 'name', 'slug'] + class BookReferenceV2ListSerializer(serializers.ModelSerializer): title = LocalizedField() - authors = BookAuthorV2Serializer(many=True, read_only=True) + authors = serializers.SerializerMethodField() tags = BookTagV2Serializer(many=True, read_only=True) number_of_volumes = serializers.SerializerMethodField() image = serializers.SerializerMethodField() @@ -29,6 +35,11 @@ class BookReferenceV2ListSerializer(serializers.ModelSerializer): model = BookReference fields = ['id', 'slug', 'title', 'authors', 'number_of_volumes', 'tags', 'image'] + def get_authors(self, obj): + if obj.author: + return [BookAuthorV2Serializer(obj.author, context=self.context).data] + return [] + def get_number_of_volumes(self, obj): return obj.volumes.count() @@ -48,12 +59,14 @@ class BookEditionV2Serializer(serializers.ModelSerializer): notes = LocalizedField() tags = LocalizedField() publication_place = serializers.SerializerMethodField() + researchers = BookResearcherV2Serializer(many=True, read_only=True) class Meta: model = BookEdition fields = [ 'id', 'publisher', 'publication_place', 'edition_number', - 'year_of_publication', 'number_of_volumes', 'notes', 'source_url', 'tags' + 'year_of_publication', 'number_of_volumes', 'notes', 'source_url', 'tags', + 'researchers' ] def get_publication_place(self, obj): @@ -83,7 +96,7 @@ class BookVolumeV2Serializer(serializers.ModelSerializer): class BookReferenceV2DetailSerializer(serializers.ModelSerializer): title = LocalizedField() - authors = BookAuthorV2Serializer(many=True, read_only=True) + authors = serializers.SerializerMethodField() image = serializers.SerializerMethodField() information = serializers.SerializerMethodField() @@ -94,6 +107,11 @@ class BookReferenceV2DetailSerializer(serializers.ModelSerializer): model = BookReference fields = ['id', 'title', 'authors', 'image', 'information', 'excerpts', 'volumes'] + def get_authors(self, obj): + if obj.author: + return [BookAuthorV2Serializer(obj.author, context=self.context).data] + return [] + def get_image(self, obj): first_image = obj.images.filter(book_volume__isnull=True).order_by('order').first() if not first_image: @@ -166,7 +184,7 @@ class BookReferenceV2DetailSerializer(serializers.ModelSerializer): class BookReferenceV2SyncSerializer(serializers.ModelSerializer): title = LocalizedField() - authors = BookAuthorV2Serializer(many=True, read_only=True) + authors = serializers.SerializerMethodField() attributes = BookAttributeSerializer(many=True, read_only=True) images = BookReferenceImageSerializer(many=True, read_only=True) @@ -181,6 +199,11 @@ class BookReferenceV2SyncSerializer(serializers.ModelSerializer): 'attributes', 'images', 'information', 'hadises', 'volumes' ] + def get_authors(self, obj): + if obj.author: + return [BookAuthorV2Serializer(obj.author, context=self.context).data] + return [] + def get_information(self, obj): request = self.context.get("request") summary = get_localized_text(obj.description, request) if obj.description else "" @@ -265,7 +288,7 @@ class AuthorBookReferenceSerializer(serializers.ModelSerializer): def get_authors(self, obj): field = LocalizedField() field._context = self.context - return [field.to_representation(author.name) for author in obj.authors.all()] + return [field.to_representation(obj.author.name)] if obj.author else [] def get_thumbnail(self, obj): # گرفتن اولین عکس آپلود شده برای این رفرنس diff --git a/apps/hadis/serializers/serializers_admin.py b/apps/hadis/serializers/serializers_admin.py index 1e15cfd..84db34e 100644 --- a/apps/hadis/serializers/serializers_admin.py +++ b/apps/hadis/serializers/serializers_admin.py @@ -4,7 +4,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile from utils.image_compression import maybe_compress_uploaded_file from ..models import ( Hadis, HadisCategory, HadisStatus, HadisTag, HadisCorrection, HadisInterpretation, HadisCollection, HadisSect, HadisInCollection, HadisTransmitter, - BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType, BookEdition, BookVolume, + BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType, BookEdition, BookVolume, BookResearcher, Transmitters, TransmitterReliability, NarratorLayer, OpinionStatus, TransmitterOpinion, TransmitterOriginalText, CorrectionReference, CorrectionReferenceImage, InterpretationReference, InterpretationReferenceImage, OriginalTextReference, OriginalTextReferenceImage @@ -823,7 +823,7 @@ class AdminBookReferenceListSerializer(serializers.ModelSerializer): class AdminBookReferenceDetailSerializer(serializers.ModelSerializer): subject_area_detail = AdminBookSubjectAreaSerializer(source="subject_area", many=True, read_only=True) type_detail = AdminBookTypeSerializer(source="type", read_only=True) - authors_detail = AdminBookAuthorSerializer(source="authors", many=True, read_only=True) + author_detail = AdminBookAuthorSerializer(source="author", read_only=True) subject_area = serializers.PrimaryKeyRelatedField( queryset=BookSubjectArea.objects.all(), @@ -835,10 +835,10 @@ class AdminBookReferenceDetailSerializer(serializers.ModelSerializer): required=False, allow_null=True, ) - authors = serializers.PrimaryKeyRelatedField( + author = serializers.PrimaryKeyRelatedField( queryset=BookAuthor.objects.all(), - many=True, required=False, + allow_null=True, ) source_url = serializers.SerializerMethodField() @@ -908,13 +908,12 @@ class AdminBookReferenceDetailSerializer(serializers.ModelSerializer): "type", "type_detail", "order", - "researcher", "city_of_publication", "country_of_publication", "edition_number", "rate", - "authors", - "authors_detail", + "author", + "author_detail", "created_at", "updated_at", "share_link", @@ -923,22 +922,16 @@ class AdminBookReferenceDetailSerializer(serializers.ModelSerializer): def create(self, validated_data): subject_area = validated_data.pop("subject_area", []) - authors = validated_data.pop("authors", []) book = super().create(validated_data) if subject_area: book.subject_area.set(subject_area) - if authors: - book.authors.set(authors) return book def update(self, instance, validated_data): subject_area = validated_data.pop("subject_area", None) - authors = validated_data.pop("authors", None) book = super().update(instance, validated_data) if subject_area is not None: book.subject_area.set(subject_area) - if authors is not None: - book.authors.set(authors) return book @@ -1171,6 +1164,15 @@ class AdminBookVolumeSerializer(serializers.ModelSerializer): ] +class AdminBookResearcherSerializer(serializers.ModelSerializer): + id = serializers.IntegerField(required=False) + name = serializers.JSONField(required=False, default=list) + + class Meta: + model = BookResearcher + fields = ["id", "name", "slug", "author"] + + class AdminBookEditionSerializer(serializers.ModelSerializer): publisher = serializers.JSONField(required=False, default=list) city_of_publication = serializers.JSONField(required=False, default=list) @@ -1179,6 +1181,7 @@ class AdminBookEditionSerializer(serializers.ModelSerializer): tags = serializers.JSONField(required=False, default=list) volumes_detail = AdminBookVolumeSerializer(source="volumes", many=True, read_only=True) number_of_volumes = serializers.SerializerMethodField() + researchers = AdminBookResearcherSerializer(many=True, required=False) class Meta: model = BookEdition @@ -1196,9 +1199,40 @@ class AdminBookEditionSerializer(serializers.ModelSerializer): "notes", "tags", "volumes_detail", + "researchers", "created_at", "updated_at", ] def get_number_of_volumes(self, obj): return obj.volumes.count() + + def create(self, validated_data): + researchers_data = validated_data.pop("researchers", []) + edition = super().create(validated_data) + for res_data in researchers_data: + BookResearcher.objects.create(book_edition=edition, **res_data) + return edition + + def update(self, instance, validated_data): + researchers_data = validated_data.pop("researchers", None) + edition = super().update(instance, validated_data) + if researchers_data is not None: + # Delete researchers no longer in the request payload + keep_ids = [r.get("id") for r in researchers_data if r.get("id")] + instance.researchers.exclude(id__in=keep_ids).delete() + for res_data in researchers_data: + res_id = res_data.get("id") + if res_id: + # Update existing researcher + res_data_clean = {k: v for k, v in res_data.items() if k != "id"} + # Filter and update + BookResearcher.objects.filter(id=res_id, book_edition=instance).update(**res_data_clean) + # Trigger save to execute save() hook (for author update propagation if author is changed) + res_obj = BookResearcher.objects.filter(id=res_id, book_edition=instance).first() + if res_obj: + res_obj.save() + else: + # Create new researcher + BookResearcher.objects.create(book_edition=instance, **res_data) + return edition diff --git a/apps/hadis/views/hadis.py b/apps/hadis/views/hadis.py index e2af447..4994bcf 100644 --- a/apps/hadis/views/hadis.py +++ b/apps/hadis/views/hadis.py @@ -124,7 +124,7 @@ class HadisSyncView(ListAPIView): queryset=HadisReference.objects .select_related('book_reference') .prefetch_related( - 'book_reference__authors', + 'book_reference__author', Prefetch( 'images', queryset=ReferenceImage.objects.order_by('priority') @@ -135,7 +135,7 @@ class HadisSyncView(ListAPIView): Prefetch( 'hadiscorrection_set', queryset=HadisCorrection.objects.prefetch_related( - 'references__book_reference__authors', + 'references__book_reference__author', 'references__edition', 'references__book_volume', 'references__images' @@ -145,7 +145,7 @@ class HadisSyncView(ListAPIView): Prefetch( 'category__interpretations', queryset=HadisInterpretation.objects.prefetch_related( - 'references__book_reference__authors', + 'references__book_reference__author', 'references__edition', 'references__book_volume', 'references__images' @@ -530,7 +530,7 @@ class HadisDetailView(RetrieveAPIView): ).prefetch_related( 'tags', 'references__book_reference', - 'references__book_reference__authors', + 'references__book_reference__author', 'references__images', ) @@ -811,15 +811,14 @@ class HadisFiltersSyncAPIView(APIView): # ۳. منابع / کتاب‌ها sources = [] - # استفاده از prefetch_related برای جلوگیری از مشکل N+1 Query هنگام گرفتن نویسنده‌ها - books = BookReference.objects.prefetch_related('authors').all().order_by('order', '-id') + # استفاده از select_related برای جلوگیری از مشکل N+1 Query هنگام گرفتن نویسنده‌ها + books = BookReference.objects.select_related('author').all().order_by('order', '-id') for book in books: # استخراج نام نویسنده‌ها برای سرچ آفلاین فلاتر authors_names = [ - get_localized_text(author.name, request=request, language_code=lang) or "" - for author in book.authors.all() - ] + get_localized_text(book.author.name, request=request, language_code=lang) or "" + ] if book.author else [] sources.append({ "id": book.id, @@ -880,7 +879,7 @@ class HadisCorrectionDetailView(RetrieveAPIView): return HadisCorrection.objects.all().select_related( 'hadis' ).prefetch_related( - 'references__book_reference__authors', + 'references__book_reference__author', 'references__edition', 'references__book_volume', 'references__images' @@ -905,7 +904,7 @@ class HadisInterpretationDetailView(RetrieveAPIView): return HadisInterpretation.objects.all().select_related( 'category' ).prefetch_related( - 'references__book_reference__authors', + 'references__book_reference__author', 'references__edition', 'references__book_volume', 'references__images' diff --git a/apps/hadis/views/reference_v2.py b/apps/hadis/views/reference_v2.py index bc5a027..4bfb5e1 100644 --- a/apps/hadis/views/reference_v2.py +++ b/apps/hadis/views/reference_v2.py @@ -16,8 +16,8 @@ class BookReferenceV2DetailView(generics.RetrieveAPIView): return ( BookReference.objects .filter(slug=self.kwargs.get('slug')) + .select_related('author') .prefetch_related( - 'authors', 'editions__volumes__images', 'volumes__images', 'images', @@ -55,8 +55,8 @@ class BookReferenceV2SyncView(generics.ListAPIView): return super().get(request, *args, **kwargs) def get_queryset(self): - qs = BookReference.objects.select_related().prefetch_related( - 'authors', 'attributes', 'images', 'editions__volumes', 'volumes', 'hadis_references__hadis' + qs = BookReference.objects.select_related('author').prefetch_related( + 'attributes', 'images', 'editions__volumes', 'volumes', 'hadis_references__hadis' ).distinct().order_by('id') category = self.request.query_params.get('category') @@ -65,11 +65,14 @@ class BookReferenceV2SyncView(generics.ListAPIView): author = self.request.query_params.get('author') if author: - qs = qs.filter(authors__id=author) + qs = qs.filter(author_id=author) - sect = self.request.query_params.get('sect') - if sect: - qs = qs.filter(type__id=sect) + madhab = self.request.query_params.get('madhab') + if madhab: + if madhab in ['shia', 'sunni']: + qs = qs.filter(type__sect=madhab) + else: + qs = qs.filter(type__id=madhab) pdf_available = self.request.query_params.get('pdf_available') if pdf_available == 'true': @@ -80,12 +83,12 @@ class BookReferenceV2SyncView(generics.ListAPIView): century = self.request.query_params.get('century') if century: if century == 'before_islam': - qs = qs.filter(authors__death_year_hijri__lt=0) + qs = qs.filter(author__death_year_hijri__lt=0) elif century.isdigit(): century_num = int(century) start_year = (century_num - 1) * 100 + 1 end_year = century_num * 100 - qs = qs.filter(authors__death_year_hijri__gte=start_year, authors__death_year_hijri__lte=end_year) + qs = qs.filter(author__death_year_hijri__gte=start_year, author__death_year_hijri__lte=end_year) return qs @@ -142,7 +145,7 @@ class BookReferenceV2ListView(generics.ListAPIView): return super().get(request, *args, **kwargs) def get_queryset(self): - qs = BookReference.objects.prefetch_related('authors', 'tags', 'volumes__images').distinct().order_by('-created_at') + qs = BookReference.objects.select_related('author').prefetch_related('tags', 'volumes__images').order_by('-created_at') search = self.request.query_params.get('search') if search: @@ -150,7 +153,7 @@ class BookReferenceV2ListView(generics.ListAPIView): qs = qs.filter( Q(title__icontains=search) | Q(description__icontains=search) | - Q(authors__name__icontains=search) + Q(author__name__icontains=search) ) category = self.request.query_params.get('category') @@ -159,7 +162,7 @@ class BookReferenceV2ListView(generics.ListAPIView): author = self.request.query_params.get('author') if author: - qs = qs.filter(authors__id=author) + qs = qs.filter(author_id=author) madhab = self.request.query_params.get('madhab') if madhab: @@ -287,8 +290,8 @@ class AuthorReferencesListView(ListAPIView): # پیدا کردن رفرنس‌هایی که این نویسنده جزو authors آن‌هاست return BookReference.objects.filter( - authors__slug=author_slug - ).prefetch_related('authors', 'images').distinct().order_by('-created_at') + author__slug=author_slug + ).select_related('author').prefetch_related('images').order_by('-created_at') class BookAuthorSyncView(generics.ListAPIView): """ diff --git a/apps/hadis/views/transmitter.py b/apps/hadis/views/transmitter.py index b3d2520..cb55d29 100644 --- a/apps/hadis/views/transmitter.py +++ b/apps/hadis/views/transmitter.py @@ -146,7 +146,7 @@ class TransmitterSyncView(ListAPIView): 'originaltexts', # 👇 ۳. اضافه کردن 'transmitter' برای جلوگیری از کوئری چرخشی در DetailSerializer متون اصلی queryset=TransmitterOriginalText.objects.select_related('transmitter').prefetch_related( - 'references__book_reference__authors', + 'references__book_reference__author', 'references__edition', 'references__book_volume', 'references__images' @@ -483,7 +483,7 @@ class TransmitterOriginalTextDetailView(RetrieveAPIView): return TransmitterOriginalText.objects.all().select_related( 'transmitter' ).prefetch_related( - 'references__book_reference__authors', + 'references__book_reference__author', 'references__edition', 'references__book_volume', 'references__images' diff --git a/apps/hadis/views_admin.py b/apps/hadis/views_admin.py index 63a9c41..b6579d9 100644 --- a/apps/hadis/views_admin.py +++ b/apps/hadis/views_admin.py @@ -511,7 +511,7 @@ class AdminBookReferenceViewSet(ModelViewSet): return AdminBookReferenceDetailSerializer def get_queryset(self): - queryset = BookReference.objects.all().prefetch_related("subject_area", "authors", "volumes", "editions").select_related("type") + queryset = BookReference.objects.all().prefetch_related("subject_area", "volumes", "editions").select_related("type", "author") search_query = self.request.query_params.get("search") if search_query: @@ -521,7 +521,6 @@ class AdminBookReferenceViewSet(ModelViewSet): | Q(isbn__icontains=search_query) | Q(publisher__icontains=search_query) | Q(description__icontains=search_query) - | Q(researcher__icontains=search_query) ) type_id = self.request.query_params.get("type") @@ -538,7 +537,7 @@ class AdminBookReferenceViewSet(ModelViewSet): author_id = self.request.query_params.get("author") if author_id and author_id != "all": - queryset = queryset.filter(authors__id=author_id) + queryset = queryset.filter(author_id=author_id) return queryset.distinct().order_by("-created_at")