You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

222 lines
8.7 KiB

from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from django.http import JsonResponse
from django.urls import path
from django.db import models
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.urls import reverse
from unfold.admin import ModelAdmin
from unfold.decorators import display
from dj_category.admin import BaseCategoryAdmin
from ajaxdatatable.admin import AjaxDatatable
from django.db.models import Case, When, Value
from django.utils.html import format_html
from apps.hadis.models import HadisCategory
from utils.admin import project_admin_site
@admin.register(HadisCategory)
class HadisCategoryAdmin(BaseCategoryAdmin, ModelAdmin):
change_form_template = 'admin/hadiscategory/change_form.html'
change_list_template = 'admin/category_index.html'
fieldsets = (
(None, {
'fields': ('name', 'source_type', 'category_type', 'parent', 'is_active', 'order'),
'classes': ('unfold-fieldset',),
}),
)
search_fields = ['name']
list_display = ['name', 'source_type_badge', 'category_type', 'parent', 'is_active', 'order']
list_filter = ['source_type', 'category_type', 'is_active']
@display(description=_("Source Type"))
def source_type_badge(self, obj):
badge_classes = {
'quran': 'unfold-badge unfold-badge--success',
'hadith': 'unfold-badge unfold-badge--info',
'book': 'unfold-badge unfold-badge--warning',
# Add more source types as needed
}
badge_class = badge_classes.get(obj.source_type, 'unfold-badge')
return format_html('<span class="{}">{}</span>', badge_class, obj.get_source_type_display())
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
return form
def get_urls(self):
urls = super().get_urls()
custom_urls = [
path('categories-ajax/hadiscategory/', self.admin_site.admin_view(self.ajax_categories), name='hadiscategory_ajax_categories'),
]
return custom_urls + urls
def get_categories_groupby_language(self, request=None, selected_values=(), is_multiple=False):
return super().get_categories(request, selected_values, is_multiple)
def ajax_update(self, request):
data = request.POST
src_node = self.model.objects.get(pk=int(data['srcNode']))
other_node = self.model.objects.get(pk=int(data['otherNode']))
if src_node.slug in self.base_categories or other_node.slug in self.base_categories:
return JsonResponse({'data': _('This item can not be modified')}, status=401)
mode = data['hitMode']
if mode == 'over':
src_node.move_to(other_node, 'first-child')
elif mode == 'after':
src_node.move_to(other_node, 'right')
elif mode == 'before':
src_node.move_to(other_node, 'left')
return JsonResponse({'data': 'ok'}, safe=False)
def get_categories(self, request=None, selected_values=(), is_multiple=False):
"""
Override the get_categories method to filter by source_type if provided in the request
"""
categories = super().get_categories(request, selected_values, is_multiple)
# If request has source_type parameter, filter the categories
if request and request.GET.get('source_type'):
source_type = request.GET.get('source_type')
# Filter the categories by source_type
filtered_categories = []
for category in categories:
# If it's a dictionary (serialized category)
if isinstance(category, dict) and category.get('source_type') == source_type:
filtered_categories.append(category)
# If it's a model instance
elif hasattr(category, 'source_type') and getattr(category, 'source_type') == source_type:
filtered_categories.append(category)
return filtered_categories
return categories
def ajax_categories(self, request):
"""
Handle AJAX request for categories with source_type filtering and search
"""
# Get source_type from request
source_type = request.GET.get('source_type')
# Get node_id if provided (for single node data)
node_id = request.GET.get('node_id')
# Get search term if provided
search = request.GET.get('search')
# Get parent level filter if provided
parent_level = request.GET.get('parent_level')
if node_id:
# Return data for a specific node
try:
node = self.model.objects.get(pk=int(node_id))
return JsonResponse({
'id': node.id,
'source_type': node.source_type,
'category_type': node.category_type,
'parent': node.parent_id,
'level': node.level_p # Add the level_p property
})
except self.model.DoesNotExist:
return JsonResponse({'error': 'Node not found'}, status=404)
# Get all categories
queryset = self.model.objects.all()
# Annotate queryset with level_p
queryset = queryset.annotate(
level_pp=Case(
When(parent=None, then=Value(1)),
When(parent__isnull=False, parent__parent=None, then=Value(2)),
default=Value(3),
output_field=models.IntegerField()
)
)
# Filter by source_type if provided
if source_type:
queryset = queryset.filter(source_type=source_type)
# Filter by search term if provided
if search:
queryset = queryset.filter(name__icontains=search)
# Filter by parent_level if provided
if parent_level and parent_level.isdigit():
# Convert to integer
level = int(parent_level)
# Filter categories by level_p
queryset = queryset.filter(level_pp=level)
# Convert queryset to list of dictionaries for JSON response
categories = []
for category in queryset:
categories.append({
'key': category.id,
'title': category.name,
'parent': category.parent_id,
'source_type': category.source_type,
'category_type': category.category_type,
'level': category.level_p,
# Add data property to store additional information
'data': {
'parent': category.parent_id,
'level': category.level_p
}
})
return JsonResponse(categories, safe=False)
def save_model(self, request, obj, form, change):
# Get the level choice from the form data
level_choice = request.POST.get('level_choice_hidden')
# Get the parent from AJAX selection if provided
ajax_parent = request.POST.get('ajax_parent')
if ajax_parent and ajax_parent.isdigit():
# Set the parent for the object
try:
parent_category = self.model.objects.get(pk=int(ajax_parent))
obj.parent = parent_category
except self.model.DoesNotExist:
pass
# Let the parent class handle the save
super().save_model(request, obj, form, change)
# Add a message to trigger tree reload via JavaScript
messages.success(request, _("Category saved successfully. Tree will be reloaded."),
extra_tags='unfold-message unfold-message--success')
# Set a flag in the request to redirect back to the category index page
request._category_saved = True
def response_add(self, request, obj, post_url_continue=None):
"""
Override to redirect back to the category index page after adding a new category
"""
if hasattr(request, '_category_saved') and request._category_saved:
return HttpResponseRedirect(reverse('admin:hadis_hadiscategory_changelist'))
return super().response_add(request, obj, post_url_continue)
def response_change(self, request, obj):
"""
Override to redirect back to the category index page after editing a category
"""
if hasattr(request, '_category_saved') and request._category_saved:
return HttpResponseRedirect(reverse('admin:hadis_hadiscategory_changelist'))
return super().response_change(request, obj)
# Register with project_admin_site if needed
# project_admin_site.register(HadisCategory, HadisCategoryAdmin)