Browse Source

feat(hadis): add multi-category and hadith filtering to category corrections endpoint

master
Mohsen Taba 2 weeks ago
parent
commit
2a44f0cf04
  1. 115
      apps/hadis/views/hadis.py

115
apps/hadis/views/hadis.py

@ -690,11 +690,13 @@ class CategoryHadisCorrectionsView(ListAPIView):
@swagger_auto_schema(
operation_summary="Get Category Hadis Corrections",
operation_description="Returns all text corrections across all hadiths belonging to a specific category, including hadis_info for each correction.",
operation_description="Returns all text corrections across all hadiths belonging to a specific category, including hadis_info for each correction. Supports filtering by multiple hadiths and/or categories.",
tags=['Dobodbi - Hadis (V2)'],
manual_parameters=[
openapi.Parameter('search', openapi.IN_QUERY, description="Search in text or narrator", type=openapi.TYPE_STRING),
openapi.Parameter('hadis_slug', openapi.IN_QUERY, description="Filter corrections by specific hadith slug", type=openapi.TYPE_STRING),
openapi.Parameter('hadis_slug', openapi.IN_QUERY, description="Filter corrections by specific hadith slug (comma-separated for multiple)", type=openapi.TYPE_STRING),
openapi.Parameter('hadis_slugs', openapi.IN_QUERY, description="Filter corrections by multiple hadith slugs (comma-separated)", type=openapi.TYPE_STRING),
openapi.Parameter('category_slugs', openapi.IN_QUERY, description="Filter corrections by multiple category slugs (comma-separated)", type=openapi.TYPE_STRING),
openapi.Parameter('is_bookmark', openapi.IN_QUERY, description="Filter only bookmarked corrections (requires auth)", type=openapi.TYPE_BOOLEAN),
]
)
@ -704,12 +706,52 @@ class CategoryHadisCorrectionsView(ListAPIView):
def get_queryset(self):
category_slug = self.kwargs.get('category_slug')
try:
category_ids = []
if category_slug:
category = HadisCategory.objects.get(slug=category_slug)
category_ids = category.get_descendants(include_self=True).values_list('id', flat=True)
hadis_ids = Hadis.objects.filter(
category_id__in=category_ids,
status=True
).values_list('id', flat=True)
category_ids = list(category.get_descendants(include_self=True).values_list('id', flat=True))
# Optional filter by multiple categories (selected subcategories or category slugs/IDs)
cat_param_keys = ['category_slugs', 'categories', 'category_slug']
cat_slug_list = []
for key in cat_param_keys:
vals = self.request.query_params.getlist(key) if hasattr(self.request.query_params, 'getlist') else []
if not vals and key in self.request.query_params:
val = self.request.query_params.get(key)
if val:
vals = [val] if isinstance(val, str) else list(val)
for v in vals:
if isinstance(v, str):
cat_slug_list.extend([s.strip() for s in v.split(',') if s.strip()])
elif isinstance(v, (list, tuple)):
cat_slug_list.extend(v)
elif v is not None:
cat_slug_list.append(str(v))
if cat_slug_list:
cat_filter = Q(slug__in=cat_slug_list)
id_list = [int(s) for s in cat_slug_list if str(s).isdigit()]
if id_list:
cat_filter |= Q(id__in=id_list)
selected_categories = HadisCategory.objects.filter(cat_filter)
selected_cat_ids = set()
for sc in selected_categories:
selected_cat_ids.update(sc.get_descendants(include_self=True).values_list('id', flat=True))
if selected_cat_ids:
if category_ids:
category_ids = list(set(category_ids).intersection(selected_cat_ids))
else:
category_ids = list(selected_cat_ids)
else:
return HadisCorrection.objects.none()
hadis_filter_kwargs = {'status': True}
if category_ids:
hadis_filter_kwargs['category_id__in'] = category_ids
hadis_ids = Hadis.objects.filter(**hadis_filter_kwargs).values_list('id', flat=True)
queryset = HadisCorrection.objects.filter(
hadis_id__in=hadis_ids
@ -731,10 +773,30 @@ class CategoryHadisCorrectionsView(ListAPIView):
)
queryset = queryset.filter(search_conditions)
# Optional filter by specific hadith slug within this category
hadis_slug = self.request.query_params.get('hadis_slug', None)
if hadis_slug:
queryset = queryset.filter(hadis__slug=hadis_slug)
# Optional filter by specific hadith slug(s) or ID(s)
hadis_param_keys = ['hadis_slug', 'hadis_slugs', 'hadiths']
hadis_slug_list = []
for key in hadis_param_keys:
vals = self.request.query_params.getlist(key) if hasattr(self.request.query_params, 'getlist') else []
if not vals and key in self.request.query_params:
val = self.request.query_params.get(key)
if val:
vals = [val] if isinstance(val, str) else list(val)
for v in vals:
if isinstance(v, str):
hadis_slug_list.extend([s.strip() for s in v.split(',') if s.strip()])
elif isinstance(v, (list, tuple)):
hadis_slug_list.extend(v)
elif v is not None:
hadis_slug_list.append(str(v))
if hadis_slug_list:
hadis_query = Q(hadis__slug__in=hadis_slug_list)
id_list = [int(s) for s in hadis_slug_list if str(s).isdigit()]
if id_list:
hadis_query |= Q(hadis__id__in=id_list)
queryset = queryset.filter(hadis_query)
# Filter by bookmarks if provided
is_bookmark = self.request.query_params.get('is_bookmark', '').lower()
@ -754,15 +816,44 @@ class CategoryHadisCorrectionsView(ListAPIView):
def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)
category_slug = self.kwargs.get('category_slug')
category_obj = HadisCategory.objects.filter(slug=category_slug).first()
category_obj = HadisCategory.objects.filter(slug=category_slug).first() if category_slug else None
category_data = SimpleCategory(category_obj, context={'request': request}).data if category_obj else None
available_hadiths = []
available_categories = []
if category_obj:
cat_ids = category_obj.get_descendants(include_self=True).values_list('id', flat=True)
hadiths_in_cat = Hadis.objects.filter(
category_id__in=cat_ids,
status=True
).order_by('number', 'id')
for h in hadiths_in_cat:
h_title = get_localized_text(h.title, request) if hasattr(h, 'title') and h.title else f"Hadith {h.number}"
available_hadiths.append({
"id": h.id,
"number": h.number,
"slug": h.slug,
"title": h_title,
})
subcats = category_obj.get_children() if hasattr(category_obj, 'get_children') else category_obj.children.all()
for sc in subcats:
sc_title = get_localized_text(sc.title, request) if hasattr(sc, 'title') and sc.title else sc.slug
available_categories.append({
"id": sc.id,
"slug": sc.slug,
"title": sc_title,
})
if isinstance(response.data, dict):
ordered_data = {
'count': response.data.get('count', 0),
'next': response.data.get('next'),
'previous': response.data.get('previous'),
'current_category': category_data,
'available_hadiths': available_hadiths,
'available_categories': available_categories,
'results': response.data.get('results', []),
}
response.data = ordered_data

Loading…
Cancel
Save