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.
 
 

440 lines
16 KiB

from django.contrib import admin
<<<<<<< HEAD
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)
=======
from django import forms
from django.utils.translation import gettext_lazy as _
from django.utils.html import format_html
from unfold.admin import ModelAdmin
from unfold.decorators import display, action
from mptt.admin import DraggableMPTTAdmin
from utils.json_editor_field import JsonEditorWidget
import json
from utils.admin import dovoodi_admin_site
from ..models import HadisSect, HadisCategory
# Custom Forms for JSON Fields
class HadisSectAdminForm(forms.ModelForm):
"""Custom form for HadisSect with JSON editor widgets"""
class Meta:
model = HadisSect
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for description JSON field
description_schema = {
"type": "array",
"title": "Descriptions",
"items": {
"type": "object",
"title": "Description",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Description Text"
}
},
"required": ["language_code", "text"]
}
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
self.fields['description'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(description_schema),
'title': 'Descriptions'
})
class HadisCategoryAdminForm(forms.ModelForm):
"""Custom form for HadisCategory with JSON editor widgets"""
class Meta:
model = HadisCategory
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Schema for title JSON field
title_schema = {
"type": "array",
"title": "Titles",
"items": {
"type": "object",
"title": "Title",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Title Text"
}
},
"required": ["language_code", "text"]
}
}
# Schema for description JSON field
description_schema = {
"type": "array",
"title": "Descriptions",
"items": {
"type": "object",
"title": "Description",
"properties": {
"language_code": {
"type": "string",
"title": "Language Code",
"enum": ["en", "fa", "ar", "ur", "ru"],
"options": {
"enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"]
}
},
"text": {
"type": "string",
"title": "Description Text"
}
},
"required": ["language_code", "text"]
}
}
# Apply JSON editor widgets
self.fields['title'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(title_schema),
'title': 'Titles'
})
self.fields['description'].widget = JsonEditorWidget(attrs={
'schema': json.dumps(description_schema),
'title': 'Descriptions'
})
class HadisSectAdmin(ModelAdmin):
"""Admin for HadisSect model"""
form = HadisSectAdminForm
list_display = ('sect_type', 'display_title', 'is_active', 'order')
list_filter = ('sect_type', 'is_active')
search_fields = ('title',)
ordering = ('order',)
fieldsets = (
(None, {
'fields': ('sect_type', 'title', 'is_active', 'order','description')
}),
)
def display_title(self, obj):
"""Extracts text from the title JSON list"""
try:
return obj.title[0]['text']
except (IndexError, KeyError, TypeError, AttributeError):
return "No Title"
display_title.short_description = _('Title')
class HadisCategoryAdmin(DraggableMPTTAdmin, ModelAdmin):
"""Admin for HadisCategory model with MPTT tree support"""
form = HadisCategoryAdminForm
list_display = ('indented_title', 'sect', 'source_type', 'order')
list_display_links = ('indented_title',)
list_filter = ('sect', 'source_type')
search_fields = ('title',)
ordering = ('tree_id', 'lft')
fieldsets = (
(None, {
'fields': ('parent', 'sect', 'source_type', 'title', 'order','description')
}),
(_('Files'), {
'fields': ('xmind_file',),
'classes': ('collapse',)
}),
)
def indented_title(self, instance):
"""Display indented title for tree structure using JSON text"""
try:
# Extract text from the first element of the title list
title_text = instance.title[0]['text']
except (IndexError, KeyError, TypeError, AttributeError):
title_text = "No Title"
# DraggableMPTTAdmin works best if you don't mess with the HTML too much,
# but here is your requested dash indentation style combined with clean text:
return f"{'' * instance.level} {title_text}"
indented_title.short_description = _('Title')
# Register models with the custom admin site
dovoodi_admin_site.register(HadisSect, HadisSectAdmin)
dovoodi_admin_site.register(HadisCategory, HadisCategoryAdmin)
>>>>>>> develop