Browse Source

fix(hadis): paginate book editions endpoint and remove N+1 queries

- Use OptionalPagination on AdminBookEditionViewSet (page/page_size), keep full list when not requested
- Extend edition search to title, publisher, year and connected book titles
- Add select_related/prefetch_related and use prefetched data in AdminBookEditionSerializer (54 -> 6 queries per page)
- Add books_detail field; fix editors update logic being nested under wrong condition
- Fallback book_reference to first connected book when missing
master
Mohsen Taba 1 week ago
parent
commit
d7d0c0093f
  1. 34
      apps/hadis/serializers/serializers_admin.py
  2. 18
      apps/hadis/views_admin.py

34
apps/hadis/serializers/serializers_admin.py

@ -3798,24 +3798,18 @@ class AdminBookEditionSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
ret = super().to_representation(instance)
res = instance.researchers.first()
# Use prefetched relations (no extra queries per row)
researchers = list(instance.researchers.all())
editors = list(instance.editors.all())
res = researchers[0] if researchers else None
ret["researcher_author_id"] = res.author_id if res and res.author_id else None
ed_obj = instance.editors.first()
ed_obj = editors[0] if editors else None
ret["editor_author_id"] = ed_obj.author_id if ed_obj and ed_obj.author_id else None
ret["books"] = list(instance.books.values_list('id', flat=True))
ret["books_detail"] = [
{
"id": b.id,
"title": b.title,
"slug": b.slug,
}
for b in instance.books.all()
]
ret["books"] = [b.id for b in instance.books.all()]
return ret
def get_number_of_volumes(self, obj):
return obj.volumes.count()
return len(obj.volumes.all())
def get_books_detail(self, obj):
return [
@ -3920,10 +3914,6 @@ class AdminBookEditionSerializer(serializers.ModelSerializer):
# Delete editors no longer in the request payload
keep_ids = [e.get("id") for e in editors_data if e.get("id")]
instance.editors.exclude(id__in=keep_ids).delete()
if books_data is not None:
edition.books.set(books_data)
if edition.book_reference and not edition.books.filter(id=edition.book_reference_id).exists():
edition.books.add(edition.book_reference)
for ed_data in editors_data:
ed_id = ed_data.get("id")
if ed_id:
@ -3937,6 +3927,16 @@ class AdminBookEditionSerializer(serializers.ModelSerializer):
# Create new editor
BookEditor.objects.create(book_edition=instance, **ed_data)
if books_data is not None:
edition.books.set(books_data)
if edition.book_reference and not edition.books.filter(id=edition.book_reference_id).exists():
edition.books.add(edition.book_reference)
elif not edition.book_reference and edition.books.exists():
first_b = edition.books.first()
if first_b:
edition.book_reference = first_b
edition.save(update_fields=['book_reference'])
author_links_dict = {}
if has_res_id:
author_links_dict["researcher_author_id"] = res_author_id

18
apps/hadis/views_admin.py

@ -2565,13 +2565,19 @@ class AdminBookEditionViewSet(ModelViewSet):
serializer_class = AdminBookEditionSerializer
pagination_class = None
pagination_class = OptionalPagination
def get_queryset(self):
queryset = BookEdition.objects.all().prefetch_related("books", "volumes")
queryset = BookEdition.objects.all().select_related(
"tag",
"publisher_item__city__country",
"publisher_item__country",
"city_of_publication_city__country",
"country_of_publication_country",
).prefetch_related("books", "volumes", "researchers", "editors")
book_reference_id = self.request.query_params.get("book_reference_id")
@ -2583,9 +2589,13 @@ class AdminBookEditionViewSet(ModelViewSet):
if search_query:
from django.db.models import Q
queryset = queryset.filter(
Q(title__icontains=search_query) |
Q(edition_number__icontains=search_query) |
Q(isbn__icontains=search_query)
)
Q(publisher__icontains=search_query) |
Q(year_of_publication__icontains=search_query) |
Q(isbn__icontains=search_query) |
Q(books__title__icontains=search_query)
).distinct()
return queryset.order_by("-created_at")

Loading…
Cancel
Save