Browse Source

category filtering based on has hadith or has leaf for admin panel dropdowns

master
Mohsen Taba 4 hours ago
parent
commit
11d07ede6b
  1. 8
      apps/hadis/models/category.py
  2. 9
      apps/hadis/models/hadis.py
  3. 53
      apps/hadis/serializers/serializers_admin.py
  4. 17
      apps/hadis/views_admin.py

8
apps/hadis/models/category.py

@ -99,6 +99,14 @@ class HadisCategory(LowercaseSlugMixin, MPTTModel):
f'Parent source_type: {self.parent.source_type}, ' f'Parent source_type: {self.parent.source_type}, '
f'Your source_type: {self.source_type}') f'Your source_type: {self.source_type}')
) )
if self.parent and self.parent.hadis_set.exists():
raise ValidationError(
_('Cannot set parent to a category that already contains hadiths/content items.')
)
if self.pk and self.hadis_set.exists() and self.children.exists():
raise ValidationError(
_('A category cannot have both hadiths and subcategories.')
)
slug_source_field = 'title' slug_source_field = 'title'

9
apps/hadis/models/hadis.py

@ -2,6 +2,7 @@ from enum import unique
from typing import Optional from typing import Optional
from django.db import models from django.db import models
from django.db.models import F, ForeignKey from django.db.models import F, ForeignKey
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.conf import settings from django.conf import settings
from django.utils.text import slugify from django.utils.text import slugify
@ -186,7 +187,15 @@ class Hadis(LowercaseSlugMixin, models.Model):
title = self.title[0]['text'] if self.title else f"Hadis {self.number}" title = self.title[0]['text'] if self.title else f"Hadis {self.number}"
return f"{self.number} - {title}" return f"{self.number} - {title}"
def clean(self):
super().clean()
if self.category and self.category.children.exists():
raise ValidationError(
_('Cannot assign hadith to a category that has subcategories. Only leaf categories can contain hadiths.')
)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self.clean()
# Generate slug if not already set or if slug is empty # Generate slug if not already set or if slug is empty
if not self.slug or (isinstance(self.slug, str) and self.slug.strip() == ''): if not self.slug or (isinstance(self.slug, str) and self.slug.strip() == ''):
title_text = None title_text = None

53
apps/hadis/serializers/serializers_admin.py

@ -1,5 +1,6 @@
from rest_framework import serializers from rest_framework import serializers
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from django.utils.translation import gettext_lazy as _
from utils.image_compression import maybe_compress_uploaded_file from utils.image_compression import maybe_compress_uploaded_file
from utils import absolute_https_url from utils import absolute_https_url
@ -41,11 +42,30 @@ class AdminHadisCategorySerializer(serializers.ModelSerializer):
sect_type = serializers.CharField(source='sect.sect_type', read_only=True) sect_type = serializers.CharField(source='sect.sect_type', read_only=True)
title = LocalizedField() title = LocalizedField()
description = LocalizedField() description = LocalizedField()
has_children = serializers.SerializerMethodField()
is_leaf = serializers.SerializerMethodField()
has_hadith = serializers.SerializerMethodField()
def get_has_children(self, obj):
if hasattr(obj, "annotated_has_children"):
return bool(obj.annotated_has_children)
return obj.children.exists()
def get_is_leaf(self, obj):
if hasattr(obj, "annotated_has_children"):
return not bool(obj.annotated_has_children)
return not obj.children.exists()
def get_has_hadith(self, obj):
if hasattr(obj, "annotated_has_hadith"):
return bool(obj.annotated_has_hadith)
return obj.hadis_set.exists()
class Meta: class Meta:
model = HadisCategory model = HadisCategory
fields = [ fields = [
"id", "id",
"parent",
"title", "title",
"slug", "slug",
"source_type", "source_type",
@ -53,6 +73,9 @@ class AdminHadisCategorySerializer(serializers.ModelSerializer):
"sect", "sect",
"sect_type", "sect_type",
"description", "description",
"has_children",
"is_leaf",
"has_hadith",
] ]
@ -240,6 +263,13 @@ class AdminHadisDetailSerializer(serializers.ModelSerializer):
from apps.bookmark.models.bookmark import Bookmark from apps.bookmark.models.bookmark import Bookmark
return Bookmark.objects.filter(service=Bookmark.ServiceChoices.HADITH, content_id=obj.id, status=True).count() return Bookmark.objects.filter(service=Bookmark.ServiceChoices.HADITH, content_id=obj.id, status=True).count()
def validate_category(self, value):
if value and value.children.exists():
raise serializers.ValidationError(
_("Cannot assign a hadith/item to a category that has subcategories. Only leaf categories can contain hadiths.")
)
return value
def get_collections_detail(self, obj): def get_collections_detail(self, obj):
collections = [item.collection for item in obj.collection_items.all()] collections = [item.collection for item in obj.collection_items.all()]
return AdminHadisCollectionSerializer(collections, many=True).data return AdminHadisCollectionSerializer(collections, many=True).data
@ -607,6 +637,8 @@ class AdminHadisCategoryArchiveSerializer(serializers.ModelSerializer):
xmind_file = AbsoluteFileField(required=False, allow_null=True) xmind_file = AbsoluteFileField(required=False, allow_null=True)
remove_xmind_file = serializers.BooleanField(write_only=True, required=False, default=False) remove_xmind_file = serializers.BooleanField(write_only=True, required=False, default=False)
has_hadith = serializers.SerializerMethodField() has_hadith = serializers.SerializerMethodField()
has_children = serializers.SerializerMethodField()
is_leaf = serializers.SerializerMethodField()
parent = serializers.PrimaryKeyRelatedField( parent = serializers.PrimaryKeyRelatedField(
queryset=HadisCategory.objects.all(), queryset=HadisCategory.objects.all(),
@ -619,8 +651,27 @@ class AdminHadisCategoryArchiveSerializer(serializers.ModelSerializer):
) )
def get_has_hadith(self, obj): def get_has_hadith(self, obj):
if hasattr(obj, "annotated_has_hadith"):
return bool(obj.annotated_has_hadith)
return obj.hadis_set.exists() return obj.hadis_set.exists()
def get_has_children(self, obj):
if hasattr(obj, "annotated_has_children"):
return bool(obj.annotated_has_children)
return obj.children.exists()
def get_is_leaf(self, obj):
if hasattr(obj, "annotated_has_children"):
return not bool(obj.annotated_has_children)
return not obj.children.exists()
def validate_parent(self, value):
if value and value.hadis_set.exists():
raise serializers.ValidationError(
_("Cannot set parent to a category that already contains hadiths/content items.")
)
return value
class Meta: class Meta:
model = HadisCategory model = HadisCategory
fields = [ fields = [
@ -639,6 +690,8 @@ class AdminHadisCategoryArchiveSerializer(serializers.ModelSerializer):
"share_link", "share_link",
"xmind_share_link", "xmind_share_link",
"has_hadith", "has_hadith",
"has_children",
"is_leaf",
] ]
read_only_fields = ["id", "share_link", "xmind_share_link"] read_only_fields = ["id", "share_link", "xmind_share_link"]

17
apps/hadis/views_admin.py

@ -1,5 +1,4 @@
from django.db.models import Q
from django.db.models import Q
from django.db.models import Q, Exists, OuterRef
from rest_framework.authentication import TokenAuthentication from rest_framework.authentication import TokenAuthentication
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.parsers import FormParser, JSONParser, MultiPartParser from rest_framework.parsers import FormParser, JSONParser, MultiPartParser
@ -55,7 +54,12 @@ class AdminHadisCategoryViewSet(ReadOnlyModelViewSet):
pagination_class = None pagination_class = None
def get_queryset(self): def get_queryset(self):
queryset = HadisCategory.objects.all()
hadis_subquery = Hadis.objects.filter(category=OuterRef("pk"))
children_subquery = HadisCategory.objects.filter(parent=OuterRef("pk"))
queryset = HadisCategory.objects.select_related("parent", "sect").annotate(
annotated_has_hadith=Exists(hadis_subquery),
annotated_has_children=Exists(children_subquery),
)
source_type = self.request.query_params.get("source_type") source_type = self.request.query_params.get("source_type")
if source_type: if source_type:
queryset = queryset.filter(source_type=source_type) queryset = queryset.filter(source_type=source_type)
@ -89,7 +93,12 @@ class DovodiHadisCategoryViewSet(ModelViewSet):
parser_classes = (JSONParser, MultiPartParser, FormParser) parser_classes = (JSONParser, MultiPartParser, FormParser)
def get_queryset(self): def get_queryset(self):
queryset = HadisCategory.objects.select_related("parent", "sect")
hadis_subquery = Hadis.objects.filter(category=OuterRef("pk"))
children_subquery = HadisCategory.objects.filter(parent=OuterRef("pk"))
queryset = HadisCategory.objects.select_related("parent", "sect").annotate(
annotated_has_hadith=Exists(hadis_subquery),
annotated_has_children=Exists(children_subquery),
)
search_query = self.request.query_params.get("search") search_query = self.request.query_params.get("search")
if search_query: if search_query:
queryset = queryset.filter( queryset = queryset.filter(

Loading…
Cancel
Save