from django.contrib import admin from django.utils.translation import gettext_lazy as _ from dj_category.admin import BaseCategoryAdmin from ajaxdatatable.admin import AjaxDatatable from django.http import JsonResponse from django.urls import path from apps.hadis.models import * from django import forms from django.db.models import Case, When, Value @admin.register(HadisCategory) class HadisCategoryAdmin(BaseCategoryAdmin): change_form_template = 'admin/hadiscategory/change_form.html' change_list_template = 'admin/category_index.html' fields = ( 'name', 'source_type', 'category_type' , 'parent', 'is_active', 'order' ) search_fields = ['name'] 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): print(f'--get_categories_groupby_language-> {selected_values}') 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'])) print(f'--ajax_update-> {data}') if src_node.slug in self.base_categories or other_node.slug in self.base_categories: return JsonResponse({'data': _('This item can not be modifed')}, 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 } }) print(f'-categories-->{categories}') return JsonResponse(categories, safe=False) def save_model(self, request, obj, form, change): print(f'SAVE_MODEL CALLED: {request}/ {obj} / {form} / {change}') print(f'POST DATA: {request.POST}') # Get the level choice from the form data level_choice = request.POST.get('level_choice_hidden') print(f'LEVEL CHOICE: {level_choice}') # 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 # If parent is level 1, inherit its source_type # if parent_category.level_p == 1 and level_choice == '2': # obj.source_type = parent_category.source_type print(f'AJAX PARENT SET: {parent_category.id} - {parent_category.name}') except self.model.DoesNotExist: print(f'PARENT CATEGORY NOT FOUND: {ajax_parent}') # Debug form validation if form.is_valid(): print("FORM IS VALID") else: print(f"FORM ERRORS: {form.errors}") print(f'---> {obj}') # Let the parent class handle the save super().save_model(request, obj, form, change) # Add a message to trigger tree reload via JavaScript from django.contrib import messages messages.success(request, "Category saved successfully. Tree will be reloaded.") # 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: from django.http import HttpResponseRedirect from django.urls import reverse 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: from django.http import HttpResponseRedirect from django.urls import reverse return HttpResponseRedirect(reverse('admin:hadis_hadiscategory_changelist')) return super().response_change(request, obj)