from django.contrib import admin from igny8_core.admin.base import SiteSectorAdminMixin from .models import Tasks, Images, Content from igny8_core.business.content.models import ContentTaxonomy, ContentAttribute @admin.register(Tasks) class TasksAdmin(SiteSectorAdminMixin, admin.ModelAdmin): list_display = ['title', 'site', 'sector', 'status', 'cluster', 'created_at'] list_filter = ['status', 'site', 'sector', 'cluster'] search_fields = ['title', 'description', 'keywords'] ordering = ['-created_at'] readonly_fields = ['content_type', 'content_structure', 'entity_type', 'cluster_role', 'assigned_post_id', 'post_url'] fieldsets = ( ('Basic Info', { 'fields': ('title', 'description', 'status', 'site', 'sector') }), ('Planning', { 'fields': ('cluster', 'idea', 'keywords') }), ('Deprecated Fields (Read-Only)', { 'fields': ('content_type', 'content_structure', 'entity_type', 'cluster_role', 'assigned_post_id', 'post_url'), 'classes': ('collapse',), 'description': 'These fields are deprecated. Use Content model instead.' }), ) def get_site_display(self, obj): """Safely get site name""" try: return obj.site.name if obj.site else '-' except: return '-' get_site_display.short_description = 'Site' def get_sector_display(self, obj): """Safely get sector name""" try: return obj.sector.name if obj.sector else '-' except: return '-' def get_cluster_display(self, obj): """Safely get cluster name""" try: return obj.cluster.name if obj.cluster else '-' except: return '-' get_cluster_display.short_description = 'Cluster' @admin.register(Images) class ImagesAdmin(SiteSectorAdminMixin, admin.ModelAdmin): list_display = ['get_content_title', 'site', 'sector', 'image_type', 'status', 'position', 'created_at'] list_filter = ['image_type', 'status', 'site', 'sector'] search_fields = ['content__title', 'content__meta_title', 'task__title'] ordering = ['-id'] # Sort by ID descending (newest first) def get_content_title(self, obj): """Get content title, fallback to task title if no content""" if obj.content: return obj.content.title or obj.content.meta_title or f"Content #{obj.content.id}" elif obj.task: return obj.task.title or f"Task #{obj.task.id}" return '-' get_content_title.short_description = 'Content Title' def get_site_display(self, obj): """Safely get site name""" try: return obj.site.name if obj.site else '-' except: return '-' get_site_display.short_description = 'Site' def get_sector_display(self, obj): """Safely get sector name""" try: return obj.sector.name if obj.sector else '-' except: return '-' @admin.register(Content) class ContentAdmin(SiteSectorAdminMixin, admin.ModelAdmin): list_display = ['title', 'entity_type', 'content_format', 'cluster_role', 'site', 'sector', 'source', 'sync_status', 'word_count', 'generated_at'] list_filter = ['entity_type', 'content_format', 'cluster_role', 'source', 'sync_status', 'status', 'site', 'sector', 'generated_at'] search_fields = ['title', 'meta_title', 'primary_keyword', 'task__title', 'external_url'] ordering = ['-generated_at'] readonly_fields = ['categories', 'tags'] fieldsets = ( ('Basic Info', { 'fields': ('title', 'task', 'site', 'sector', 'cluster', 'status') }), ('Content Classification', { 'fields': ('entity_type', 'content_format', 'cluster_role', 'external_type') }), ('Content', { 'fields': ('html_content', 'word_count', 'json_blocks', 'structure_data') }), ('SEO', { 'fields': ('meta_title', 'meta_description', 'primary_keyword', 'secondary_keywords') }), ('WordPress Sync', { 'fields': ('source', 'sync_status', 'external_id', 'external_url', 'sync_metadata'), 'classes': ('collapse',) }), ('Optimization', { 'fields': ('linker_version', 'optimizer_version', 'optimization_scores', 'internal_links'), 'classes': ('collapse',) }), ('Deprecated Fields (Read-Only)', { 'fields': ('categories', 'tags'), 'classes': ('collapse',), 'description': 'These fields are deprecated. Use taxonomies M2M instead.' }), ) def get_site_display(self, obj): """Safely get site name""" try: return obj.site.name if obj.site else '-' except: return '-' get_site_display.short_description = 'Site' def get_sector_display(self, obj): """Safely get sector name""" try: return obj.sector.name if obj.sector else '-' except: return '-' @admin.register(ContentTaxonomy) class ContentTaxonomyAdmin(SiteSectorAdminMixin, admin.ModelAdmin): list_display = ['name', 'taxonomy_type', 'slug', 'parent', 'external_id', 'external_taxonomy', 'sync_status', 'count', 'site', 'sector'] list_filter = ['taxonomy_type', 'sync_status', 'site', 'sector', 'parent'] search_fields = ['name', 'slug', 'description', 'external_taxonomy'] ordering = ['taxonomy_type', 'name'] filter_horizontal = ['clusters'] fieldsets = ( ('Basic Info', { 'fields': ('name', 'slug', 'taxonomy_type', 'description', 'site', 'sector') }), ('Hierarchy', { 'fields': ('parent',), 'description': 'Set parent for hierarchical taxonomies (categories).' }), ('WordPress Sync', { 'fields': ('external_id', 'external_taxonomy', 'sync_status', 'count', 'metadata') }), ('Semantic Mapping', { 'fields': ('clusters',), 'description': 'Map this taxonomy to semantic clusters for AI optimization.' }), ) def get_queryset(self, request): qs = super().get_queryset(request) return qs.select_related('parent', 'site', 'sector').prefetch_related('clusters') @admin.register(ContentAttribute) class ContentAttributeAdmin(SiteSectorAdminMixin, admin.ModelAdmin): list_display = ['name', 'value', 'attribute_type', 'content', 'cluster', 'external_id', 'source', 'site', 'sector'] list_filter = ['attribute_type', 'source', 'site', 'sector'] search_fields = ['name', 'value', 'external_attribute_name', 'content__title'] ordering = ['attribute_type', 'name'] fieldsets = ( ('Basic Info', { 'fields': ('attribute_type', 'name', 'value', 'site', 'sector') }), ('Relationships', { 'fields': ('content', 'cluster'), 'description': 'Link to content (products/services) or cluster (semantic attributes).' }), ('WordPress/WooCommerce Sync', { 'fields': ('external_id', 'external_attribute_name', 'source', 'metadata') }), ) def get_queryset(self, request): qs = super().get_queryset(request) return qs.select_related('content', 'cluster', 'site', 'sector')