Automation final fixes
This commit is contained in:
@@ -8,7 +8,7 @@ from unfold.contrib.filters.admin import (
|
||||
ChoicesDropdownFilter,
|
||||
)
|
||||
from igny8_core.admin.base import SiteSectorAdminMixin, Igny8ModelAdmin
|
||||
from .models import Tasks, Images, Content
|
||||
from .models import Tasks, Images, Content, ImagePrompts
|
||||
from igny8_core.business.content.models import ContentTaxonomy, ContentAttribute, ContentTaxonomyRelation, ContentClusterMap
|
||||
from import_export.admin import ExportMixin, ImportExportMixin
|
||||
from import_export import resources
|
||||
@@ -294,6 +294,145 @@ class ImagesAdmin(ImportExportMixin, SiteSectorAdminMixin, Igny8ModelAdmin):
|
||||
bulk_soft_delete.short_description = 'Soft delete selected images'
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Image Prompts Admin (Using Proxy Model from models.py)
|
||||
# ============================================================================
|
||||
|
||||
class ImagePromptsResource(resources.ModelResource):
|
||||
"""Resource class for exporting Image Prompts"""
|
||||
class Meta:
|
||||
model = ImagePrompts
|
||||
fields = ('id', 'content__title', 'site__name', 'sector__name', 'image_type', 'prompt', 'caption', 'status', 'created_at')
|
||||
export_order = fields
|
||||
|
||||
|
||||
@admin.register(ImagePrompts)
|
||||
class ImagePromptsAdmin(ExportMixin, SiteSectorAdminMixin, Igny8ModelAdmin):
|
||||
"""
|
||||
Specialized admin for viewing and managing image prompts.
|
||||
This provides a focused view of the prompt field from Images model.
|
||||
"""
|
||||
resource_class = ImagePromptsResource
|
||||
|
||||
list_display = ['get_content_title', 'site', 'sector', 'image_type', 'get_prompt_preview', 'status', 'created_at']
|
||||
list_filter = [
|
||||
('image_type', ChoicesDropdownFilter),
|
||||
('status', ChoicesDropdownFilter),
|
||||
('site', RelatedDropdownFilter),
|
||||
('sector', RelatedDropdownFilter),
|
||||
('created_at', RangeDateFilter),
|
||||
]
|
||||
search_fields = ['content__title', 'prompt', 'caption']
|
||||
ordering = ['-created_at']
|
||||
readonly_fields = ['get_content_title', 'site', 'sector', 'image_type', 'prompt', 'caption',
|
||||
'status', 'position', 'image_url', 'image_path', 'created_at', 'updated_at']
|
||||
|
||||
actions = [
|
||||
'bulk_export_prompts',
|
||||
'bulk_copy_prompts_to_clipboard',
|
||||
]
|
||||
|
||||
fieldsets = (
|
||||
('Content Information', {
|
||||
'fields': ('get_content_title', 'site', 'sector', 'image_type', 'position')
|
||||
}),
|
||||
('Prompt Details', {
|
||||
'fields': ('prompt', 'caption'),
|
||||
'description': 'AI-generated prompts used for image creation'
|
||||
}),
|
||||
('Image Information', {
|
||||
'fields': ('status', 'image_url', 'image_path'),
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
('Timestamps', {
|
||||
'fields': ('created_at', 'updated_at'),
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
)
|
||||
|
||||
def get_prompt_preview(self, obj):
|
||||
"""Display a truncated preview of the prompt"""
|
||||
if obj.prompt:
|
||||
return obj.prompt[:100] + '...' if len(obj.prompt) > 100 else obj.prompt
|
||||
return '-'
|
||||
get_prompt_preview.short_description = 'Prompt Preview'
|
||||
|
||||
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'
|
||||
|
||||
def get_queryset(self, request):
|
||||
"""Filter to only show images that have prompts"""
|
||||
qs = super().get_queryset(request)
|
||||
return qs.filter(prompt__isnull=False).exclude(prompt='')
|
||||
|
||||
def has_add_permission(self, request):
|
||||
"""Image prompts are created through content generation workflow"""
|
||||
return False
|
||||
|
||||
def has_change_permission(self, request, obj=None):
|
||||
"""Image prompts are read-only"""
|
||||
return False
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
"""Prevent deletion from this view (use Images admin instead)"""
|
||||
return False
|
||||
|
||||
def bulk_export_prompts(self, request, queryset):
|
||||
"""Export selected image prompts to CSV"""
|
||||
import csv
|
||||
from django.http import HttpResponse
|
||||
from datetime import datetime
|
||||
|
||||
response = HttpResponse(content_type='text/csv')
|
||||
response['Content-Disposition'] = f'attachment; filename="image_prompts_{datetime.now().strftime("%Y%m%d_%H%M%S")}.csv"'
|
||||
|
||||
writer = csv.writer(response)
|
||||
writer.writerow(['Content Title', 'Site', 'Image Type', 'Prompt', 'Caption', 'Status', 'Created'])
|
||||
|
||||
for obj in queryset:
|
||||
content_title = self.get_content_title(obj)
|
||||
site_name = obj.site.name if obj.site else '-'
|
||||
writer.writerow([
|
||||
content_title,
|
||||
site_name,
|
||||
obj.image_type,
|
||||
obj.prompt or '',
|
||||
obj.caption or '',
|
||||
obj.status,
|
||||
obj.created_at.strftime('%Y-%m-%d %H:%M:%S')
|
||||
])
|
||||
|
||||
self.message_user(request, f'{queryset.count()} image prompt(s) exported to CSV.', messages.SUCCESS)
|
||||
return response
|
||||
bulk_export_prompts.short_description = 'Export prompts to CSV'
|
||||
|
||||
def bulk_copy_prompts_to_clipboard(self, request, queryset):
|
||||
"""Generate a text summary of prompts for copying"""
|
||||
prompts_text = []
|
||||
for obj in queryset:
|
||||
content_title = self.get_content_title(obj)
|
||||
prompts_text.append(f"--- {content_title} ({obj.image_type}) ---")
|
||||
prompts_text.append(f"Prompt: {obj.prompt or 'N/A'}")
|
||||
if obj.caption:
|
||||
prompts_text.append(f"Caption: {obj.caption}")
|
||||
prompts_text.append("")
|
||||
|
||||
# Store in session for display
|
||||
request.session['prompts_export'] = '\n'.join(prompts_text)
|
||||
self.message_user(
|
||||
request,
|
||||
f'Generated text for {queryset.count()} prompt(s). Copy from the message below.',
|
||||
messages.INFO
|
||||
)
|
||||
bulk_copy_prompts_to_clipboard.short_description = 'Copy prompts as text'
|
||||
|
||||
|
||||
class ContentResource(resources.ModelResource):
|
||||
"""Resource class for importing/exporting Content"""
|
||||
class Meta:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Backward compatibility aliases - models moved to business/content/
|
||||
from igny8_core.business.content.models import Tasks, Content, Images
|
||||
from igny8_core.business.content.models import Tasks, Content, Images, ImagePrompts
|
||||
|
||||
__all__ = ['Tasks', 'Content', 'Images']
|
||||
__all__ = ['Tasks', 'Content', 'Images', 'ImagePrompts']
|
||||
|
||||
Reference in New Issue
Block a user