Browse Source

Sync references fixed n+1 and indexing

master
Mohsen Taba 5 months ago
parent
commit
2cfa8636ea
  1. 22
      apps/hadis/migrations/0067_bookreference_hadis_bookr_id_1b53f6_idx_and_more.py
  2. 4
      apps/hadis/models/hadis.py
  3. 3
      apps/hadis/models/reference.py
  4. 33
      apps/hadis/serializers/reference.py
  5. 34
      apps/hadis/views/reference.py

22
apps/hadis/migrations/0067_bookreference_hadis_bookr_id_1b53f6_idx_and_more.py

@ -0,0 +1,22 @@
# Generated by Django 4.2.27 on 2025-12-22 14:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("hadis", "0066_alter_transmitteroriginaltext_options_and_more"),
]
operations = [
migrations.AddIndex(
model_name="bookreference",
index=models.Index(fields=["id"], name="hadis_bookr_id_1b53f6_idx"),
),
migrations.AddIndex(
model_name="hadisreference",
index=models.Index(
fields=["book_reference"], name="hadis_hadis_book_re_3fb4f0_idx"
),
),
]

4
apps/hadis/models/hadis.py

@ -324,6 +324,10 @@ class HadisReference(models.Model):
description = models.JSONField(default = list , verbose_name=_('Description'))
class Meta:
indexes = [
# For fetching hadises by book
models.Index(fields=['book_reference']),
]
verbose_name = _('Hadis Reference')
verbose_name_plural = _('Hadis References')
# unique_together = ('hadis', 'book_reference')

3
apps/hadis/models/reference.py

@ -31,6 +31,9 @@ class BookReference(models.Model):
updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at'))
class Meta:
indexes = [
models.Index(fields=['id']), # Already indexed (PK)
]
verbose_name = _('Book Reference')
verbose_name_plural = _('Book References')
ordering = ('-created_at',)

33
apps/hadis/serializers/reference.py

@ -142,28 +142,14 @@ class BookReferenceSyncSerializer(serializers.ModelSerializer):
hadises = serializers.SerializerMethodField()
title = LocalizedField()
class Meta:
model = BookReference
fields = [
'id', 'title', 'rate', 'author', 'detail', 'image', 'attribute', 'hadises'
]
# def get_authors(self,obj):
# request = self.context.get('request')
# authors = []
# try:
# for author in obj.authors.all():
# authors.append({
# 'id': author.id,
# 'name': get_localized_text(author.name,request)
# })
# except:
# authors = []
# return authors
def get_detail(self, obj):
"""Get basic book information including authors and rating"""
"""Get basic book information"""
request = self.context.get('request')
return {
@ -173,28 +159,31 @@ class BookReferenceSyncSerializer(serializers.ModelSerializer):
'isbn': obj.isbn,
'number_page': obj.number_page,
'year_of_publication': obj.year_of_publication,
'number_of_pages': obj.number_page,
'volume_info': obj.volume,
'rating': obj.rate
}
def get_hadises(self, obj):
"""Get all hadises related to this book reference"""
"""Get all hadises related to this book reference (already prefetched)"""
request = self.context.get('request')
hadis_list = []
try:
# obj.hadis_references.all() is already prefetched!
for hadis_ref in obj.hadis_references.all():
hadis = hadis_ref.hadis
hadis = hadis_ref.hadis # Already prefetched, no query!
# Handle get_translation - if it's a method, call it; if field, access it
translation = hadis.get_translation if callable(hadis.get_translation) else hadis.translation
if callable(translation):
translation = translation()
hadis_list.append({
'id': hadis.id,
'title': get_localized_text(hadis.title, request),
'title_narrator': get_localized_text(hadis.title_narrator, request),
'text': get_localized_text(hadis.text, request),
'translation': get_localized_text(hadis.get_translation,request),
'translation': get_localized_text(translation, request),
'share_link': hadis.share_link
})
except:
pass
return hadis_list

34
apps/hadis/views/reference.py

@ -41,6 +41,8 @@ class BookDetailView(RetrieveAPIView):
# )
from django.db.models import Prefetch
class BookReferenceSyncView(ListAPIView):
"""
API view to sync all book reference data for offline mode
@ -54,28 +56,20 @@ class BookReferenceSyncView(ListAPIView):
return super().get(request, *args, **kwargs)
def get_queryset(self):
return BookReference.objects.prefetch_related(
"""
Prefetch ALL related data to avoid N+1 queries
"""
return (
BookReference.objects
.select_related() # If any ForeignKey fields
.prefetch_related(
'authors',
'attributes', # ← ADDED
'images', # ← ADDED
'hadis_references__hadis'
).order_by('id')
# def list(self, request, *args, **kwargs):
# queryset = self.get_queryset()
# serializer = self.get_serializer(queryset, many=True, context={'request': request})
# # Group book references by ID for easy lookup
# grouped_data = {}
# for book_data in serializer.data:
# book_id = str(book_data['id'])
# grouped_data[book_id] = book_data
# response_data = {
# 'count': queryset.count(),
# 'results': grouped_data
# }
# return Response(response_data)
)
.order_by('id')
)
class BookAttributeView(ListCreateAPIView):

Loading…
Cancel
Save