From 6f449c32c12bf041e9a6f728887f20eeb4c013f4 Mon Sep 17 00:00:00 2001 From: "IGNY8 VPS (Salman)" Date: Mon, 1 Dec 2025 05:13:53 +0000 Subject: [PATCH] taxonomy fix --- .../ai/functions/generate_content.py | 36 ++++++------- backend/igny8_core/modules/writer/admin.py | 54 ++++++++++++++++--- 2 files changed, 64 insertions(+), 26 deletions(-) diff --git a/backend/igny8_core/ai/functions/generate_content.py b/backend/igny8_core/ai/functions/generate_content.py index 60cb25f5..e6c28689 100644 --- a/backend/igny8_core/ai/functions/generate_content.py +++ b/backend/igny8_core/ai/functions/generate_content.py @@ -242,24 +242,24 @@ class GenerateContentFunction(BaseAIFunction): tag_name = tag_name.strip() if tag_name: try: - # Get or create tag taxonomy term + tag_slug = slugify(tag_name) + # Get or create tag taxonomy term using site + slug + type for uniqueness tag_obj, created = ContentTaxonomy.objects.get_or_create( site=task.site, - name=tag_name, + slug=tag_slug, taxonomy_type='tag', defaults={ - 'slug': slugify(tag_name), + 'name': tag_name, 'sector': task.sector, 'account': task.account, - 'description': '', # Required by database - 'external_taxonomy': '', # Required by database - 'sync_status': '', # Required by database - 'count': 0, # Required by database - 'metadata': {}, # Required by database + 'description': '', + 'external_taxonomy': '', + 'count': 0, + 'metadata': {}, } ) content_record.taxonomy_terms.add(tag_obj) - logger.info(f"{'Created' if created else 'Found'} and linked tag: {tag_name} (ID: {tag_obj.id})") + logger.info(f"{'Created' if created else 'Found'} and linked tag: {tag_name} (ID: {tag_obj.id}, Slug: {tag_slug})") except Exception as e: logger.error(f"Failed to add tag '{tag_name}': {e}", exc_info=True) @@ -271,24 +271,24 @@ class GenerateContentFunction(BaseAIFunction): category_name = category_name.strip() if category_name: try: - # Get or create category taxonomy term + category_slug = slugify(category_name) + # Get or create category taxonomy term using site + slug + type for uniqueness category_obj, created = ContentTaxonomy.objects.get_or_create( site=task.site, - name=category_name, + slug=category_slug, taxonomy_type='category', defaults={ - 'slug': slugify(category_name), + 'name': category_name, 'sector': task.sector, 'account': task.account, - 'description': '', # Required by database - 'external_taxonomy': '', # Required by database - 'sync_status': '', # Required by database - 'count': 0, # Required by database - 'metadata': {}, # Required by database + 'description': '', + 'external_taxonomy': '', + 'count': 0, + 'metadata': {}, } ) content_record.taxonomy_terms.add(category_obj) - logger.info(f"{'Created' if created else 'Found'} and linked category: {category_name} (ID: {category_obj.id})") + logger.info(f"{'Created' if created else 'Found'} and linked category: {category_name} (ID: {category_obj.id}, Slug: {category_slug})") except Exception as e: logger.error(f"Failed to add category '{category_name}': {e}", exc_info=True) diff --git a/backend/igny8_core/modules/writer/admin.py b/backend/igny8_core/modules/writer/admin.py index 887af600..8182ac60 100644 --- a/backend/igny8_core/modules/writer/admin.py +++ b/backend/igny8_core/modules/writer/admin.py @@ -1,7 +1,16 @@ 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 +from igny8_core.business.content.models import ContentTaxonomy, ContentAttribute, ContentTaxonomyRelation + + +class ContentTaxonomyInline(admin.TabularInline): + """Inline admin for managing content taxonomy relationships""" + model = ContentTaxonomyRelation + extra = 1 + autocomplete_fields = ['taxonomy'] + verbose_name = 'Taxonomy Term' + verbose_name_plural = 'Taxonomy Terms (Tags & Categories)' @admin.register(Tasks) @@ -90,8 +99,8 @@ class ContentAdmin(SiteSectorAdminMixin, admin.ModelAdmin): list_filter = ['content_type', 'content_structure', 'source', 'status', 'site', 'sector', 'created_at'] search_fields = ['title', 'content_html', 'external_url'] ordering = ['-created_at'] - readonly_fields = ['created_at', 'updated_at', 'word_count'] - # Note: taxonomy_terms removed from filter_horizontal because it uses a through model + readonly_fields = ['created_at', 'updated_at', 'word_count', 'get_tags_display', 'get_categories_display'] + inlines = [ContentTaxonomyInline] fieldsets = ( ('Basic Info', { @@ -100,8 +109,11 @@ class ContentAdmin(SiteSectorAdminMixin, admin.ModelAdmin): ('Content Classification', { 'fields': ('content_type', 'content_structure', 'source') }), - # Note: taxonomy_terms field removed from fieldsets because it uses ContentTaxonomyAssociation through model - # Taxonomy associations can be managed via the inline admin or separately + ('Taxonomies (Read-only - manage below)', { + 'fields': ('get_tags_display', 'get_categories_display'), + 'classes': ('collapse',), + 'description': 'View tags and categories. To add/remove, use the Taxonomy Terms section below.' + }), ('Content', { 'fields': ('content_html', 'word_count') }), @@ -124,6 +136,22 @@ class ContentAdmin(SiteSectorAdminMixin, admin.ModelAdmin): return obj.taxonomy_terms.count() get_taxonomy_count.short_description = 'Taxonomy Count' + def get_tags_display(self, obj): + """Display tags""" + tags = obj.taxonomy_terms.filter(taxonomy_type='tag') + if tags.exists(): + return ', '.join([tag.name for tag in tags]) + return 'No tags' + get_tags_display.short_description = 'Tags' + + def get_categories_display(self, obj): + """Display categories""" + categories = obj.taxonomy_terms.filter(taxonomy_type='category') + if categories.exists(): + return ', '.join([cat.name for cat in categories]) + return 'No categories' + get_categories_display.short_description = 'Categories' + def get_site_display(self, obj): """Safely get site name""" try: @@ -142,17 +170,27 @@ class ContentAdmin(SiteSectorAdminMixin, admin.ModelAdmin): @admin.register(ContentTaxonomy) class ContentTaxonomyAdmin(SiteSectorAdminMixin, admin.ModelAdmin): - list_display = ['name', 'taxonomy_type', 'slug', 'external_id', 'external_taxonomy', 'site', 'sector'] + list_display = ['name', 'taxonomy_type', 'slug', 'count', 'external_id', 'external_taxonomy', 'site', 'sector'] list_filter = ['taxonomy_type', 'site', 'sector'] search_fields = ['name', 'slug', 'external_taxonomy'] ordering = ['taxonomy_type', 'name'] + readonly_fields = ['count', 'created_at', 'updated_at'] fieldsets = ( ('Basic Info', { - 'fields': ('name', 'slug', 'taxonomy_type', 'site', 'sector') + 'fields': ('name', 'slug', 'taxonomy_type', 'description', 'site', 'sector') + }), + ('Usage', { + 'fields': ('count',), + 'description': 'Number of content items using this term' }), ('WordPress Sync', { - 'fields': ('external_id', 'external_taxonomy') + 'fields': ('external_id', 'external_taxonomy', 'metadata'), + 'classes': ('collapse',) + }), + ('Timestamps', { + 'fields': ('created_at', 'updated_at'), + 'classes': ('collapse',) }), )