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
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
|