CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-django-taggit

A reusable Django application for simple tagging with comprehensive manager and form support.

Pending
Overview
Eval results
Files

admin-interface.mddocs/

Admin Interface

Django admin integration for managing tags and tagged items. Django-taggit provides comprehensive admin interfaces for tag management, including search functionality, tag merging capabilities, and inline editing of tagged items.

Capabilities

TagAdmin

Admin interface for managing Tag objects with search, filtering, and bulk operations.

class TagAdmin(admin.ModelAdmin):
    """
    Admin interface for Tag model.
    
    Features:
    - List display with name and slug
    - Search functionality by tag name
    - Alphabetical ordering
    - Prepopulated slug field
    - Tag merging action
    """
    list_display = ["name", "slug"]
    ordering = ["name", "slug"]
    search_fields = ["name"]
    prepopulated_fields = {"slug": ["name"]}
    actions = ["render_tag_form"]
    
    def get_urls(self):
        """Add custom URLs for tag management."""
    
    def render_tag_form(self, request, queryset):
        """Admin action to merge selected tags."""
    
    def merge_tags_view(self, request):
        """View for handling tag merge operations."""
# Register the Tag admin (automatically done by django-taggit)
from django.contrib import admin
from taggit.models import Tag
from taggit.admin import TagAdmin

admin.site.register(Tag, TagAdmin)

TaggedItemInline

Inline admin for managing TaggedItem relationships within other model admin interfaces.

class TaggedItemInline(admin.StackedInline):
    """
    Inline admin for TaggedItem model.
    
    Allows editing tag relationships directly within
    the admin interface of tagged models.
    """
    model = TaggedItem
from django.contrib import admin
from taggit.admin import TaggedItemInline
from myapp.models import Article

class ArticleAdmin(admin.ModelAdmin):
    list_display = ['title', 'created_at']
    inlines = [TaggedItemInline]

admin.site.register(Article, ArticleAdmin)

Custom Model Admin Integration

Integrating tagging functionality into your model admin interfaces.

from django.contrib import admin
from taggit.models import Tag

class ArticleAdmin(admin.ModelAdmin):
    list_display = ['title', 'author', 'created_at', 'tag_list']
    list_filter = ['created_at', 'tags']
    search_fields = ['title', 'content', 'tags__name']
    
    def tag_list(self, obj):
        """Display tags in list view."""
        return ', '.join([tag.name for tag in obj.tags.all()])
    tag_list.short_description = 'Tags'
    
    def get_queryset(self, request):
        """Optimize queries for tag display."""
        return super().get_queryset(request).prefetch_related('tags')

admin.site.register(Article, ArticleAdmin)

Tag Merging

Built-in functionality for merging multiple tags into a single tag.

class MergeTagsForm(forms.Form):
    """
    Form for merging multiple tags into one.
    
    Used in the admin interface to combine duplicate
    or related tags into a single tag.
    """
    new_tag_name = forms.CharField(
        label="New Tag Name",
        max_length=100,
        help_text="Enter new or existing tag name"
    )

The tag merging process:

  1. Select multiple tags in the admin interface
  2. Choose "Merge selected tags" action
  3. Enter the target tag name
  4. All tagged items are transferred to the target tag
  5. Original tags are deleted (except the target if it already existed)

Advanced Admin Customizations

Custom admin configurations for enhanced tag management.

from django.contrib import admin
from django.db.models import Count
from taggit.models import Tag, TaggedItem

class TaggedItemAdmin(admin.ModelAdmin):
    list_display = ['tag', 'content_type', 'object_id', 'content_object']
    list_filter = ['content_type', 'tag']
    search_fields = ['tag__name']
    raw_id_fields = ['tag']

class CustomTagAdmin(admin.ModelAdmin):
    list_display = ['name', 'slug', 'usage_count', 'created_at']
    list_filter = ['created_at']
    search_fields = ['name', 'slug']
    readonly_fields = ['slug', 'usage_count']
    ordering = ['-usage_count', 'name']
    
    def usage_count(self, obj):
        """Show how many times tag is used."""
        return obj.tagged_items.count()
    usage_count.short_description = 'Usage Count'
    usage_count.admin_order_field = 'tagged_items__count'
    
    def get_queryset(self, request):
        """Annotate with usage count for sorting."""
        return super().get_queryset(request).annotate(
            usage_count=Count('tagged_items')
        )

# Register custom admin
admin.site.unregister(Tag)
admin.site.register(Tag, CustomTagAdmin)
admin.site.register(TaggedItem, TaggedItemAdmin)

Filtering and Search

Advanced filtering and search capabilities in the admin interface.

from django.contrib import admin
from django.db.models import Q

class TagFilter(admin.SimpleListFilter):
    title = 'Tag'
    parameter_name = 'tag'

    def lookups(self, request, model_admin):
        """Provide tag options for filtering."""
        tags = Tag.objects.all().order_by('name')[:50]  # Limit for performance
        return [(tag.id, tag.name) for tag in tags]

    def queryset(self, request, queryset):
        """Filter queryset by selected tag."""
        if self.value():
            return queryset.filter(tags__id=self.value())
        return queryset

class PopularTagFilter(admin.SimpleListFilter):
    title = 'Tag Popularity'
    parameter_name = 'popularity'

    def lookups(self, request, model_admin):
        return [
            ('popular', 'Popular (10+ uses)'),
            ('moderate', 'Moderate (5-9 uses)'),
            ('rare', 'Rare (1-4 uses)'),
            ('unused', 'Unused'),
        ]

    def queryset(self, request, queryset):
        from django.db.models import Count
        
        if self.value() == 'popular':
            return queryset.annotate(
                usage=Count('tagged_items')
            ).filter(usage__gte=10)
        elif self.value() == 'moderate':
            return queryset.annotate(
                usage=Count('tagged_items')
            ).filter(usage__range=(5, 9))
        elif self.value() == 'rare':
            return queryset.annotate(
                usage=Count('tagged_items')
            ).filter(usage__range=(1, 4))
        elif self.value() == 'unused':
            return queryset.filter(tagged_items__isnull=True)
        return queryset

class ArticleAdmin(admin.ModelAdmin):
    list_display = ['title', 'author', 'tag_list']
    list_filter = [TagFilter, 'created_at']
    search_fields = ['title', 'content', 'tags__name']
    
    def tag_list(self, obj):
        return ', '.join([tag.name for tag in obj.tags.all()[:3]])
    tag_list.short_description = 'Tags'

Bulk Operations

Implementing bulk operations for tag management in the admin.

from django.contrib import admin, messages
from django.shortcuts import redirect

class BulkTagAdmin(admin.ModelAdmin):
    actions = ['add_tag_to_selected', 'remove_tag_from_selected', 'clear_tags_from_selected']
    
    def add_tag_to_selected(self, request, queryset):
        """Add a specific tag to selected objects."""
        tag_name = "bulk-processed"  # Could be made configurable
        count = 0
        for obj in queryset:
            obj.tags.add(tag_name)
            count += 1
        messages.success(request, f'Added tag "{tag_name}" to {count} objects.')
    add_tag_to_selected.short_description = 'Add "bulk-processed" tag to selected items'
    
    def remove_tag_from_selected(self, request, queryset):
        """Remove a specific tag from selected objects."""
        tag_name = "draft"
        count = 0
        for obj in queryset:
            obj.tags.remove(tag_name)
            count += 1
        messages.success(request, f'Removed tag "{tag_name}" from {count} objects.')
    remove_tag_from_selected.short_description = 'Remove "draft" tag from selected items'
    
    def clear_tags_from_selected(self, request, queryset):
        """Clear all tags from selected objects."""
        count = 0
        for obj in queryset:
            obj.tags.clear()
            count += 1
        messages.success(request, f'Cleared all tags from {count} objects.')
    clear_tags_from_selected.short_description = 'Clear all tags from selected items'

class ArticleAdmin(BulkTagAdmin):
    list_display = ['title', 'author', 'tag_list']
    # ... other configurations

Custom Admin Templates

Customizing admin templates for enhanced tag management interfaces.

<!-- admin/taggit/tag/change_list.html -->
{% extends "admin/change_list.html" %}

{% block extrahead %}
    {{ block.super }}
    <style>
        .tag-usage-high { background-color: #d4edda; }
        .tag-usage-medium { background-color: #fff3cd; }
        .tag-usage-low { background-color: #f8d7da; }
    </style>
{% endblock %}

{% block result_list %}
    <script>
        // Add visual indicators for tag usage
        document.addEventListener('DOMContentLoaded', function() {
            const rows = document.querySelectorAll('tbody tr');
            rows.forEach(function(row) {
                const usageCell = row.querySelector('td:nth-child(3)');
                if (usageCell) {
                    const usage = parseInt(usageCell.textContent);
                    if (usage >= 10) {
                        row.classList.add('tag-usage-high');
                    } else if (usage >= 5) {
                        row.classList.add('tag-usage-medium');
                    } else if (usage > 0) {
                        row.classList.add('tag-usage-low');
                    }
                }
            });
        });
    </script>
    {{ block.super }}
{% endblock %}

Tag Statistics Dashboard

Creating a custom admin view for tag statistics and management.

from django.contrib import admin
from django.urls import path
from django.shortcuts import render
from django.db.models import Count
from taggit.models import Tag

class TagStatsAdmin(admin.ModelAdmin):
    change_list_template = 'admin/tag_stats.html'
    
    def changelist_view(self, request, extra_context=None):
        # Tag statistics
        tag_stats = Tag.objects.annotate(
            usage_count=Count('tagged_items')
        ).order_by('-usage_count')
        
        popular_tags = tag_stats[:10]
        unused_tags = tag_stats.filter(usage_count=0)
        
        extra_context = extra_context or {}
        extra_context.update({
            'popular_tags': popular_tags,
            'unused_tags_count': unused_tags.count(),
            'total_tags': tag_stats.count(),
        })
        
        return super().changelist_view(request, extra_context=extra_context)

# Register with custom admin
admin.site.unregister(Tag)
admin.site.register(Tag, TagStatsAdmin)
<!-- templates/admin/tag_stats.html -->
{% extends "admin/change_list.html" %}

{% block content_title %}
    <h1>Tag Statistics</h1>
{% endblock %}

{% block result_list %}
    <div class="results">
        <div class="stats-summary">
            <h2>Summary</h2>
            <p>Total Tags: {{ total_tags }}</p>
            <p>Unused Tags: {{ unused_tags_count }}</p>
        </div>
        
        <div class="popular-tags">
            <h2>Most Popular Tags</h2>
            <table>
                <thead>
                    <tr>
                        <th>Tag</th>
                        <th>Usage Count</th>
                    </tr>
                </thead>
                <tbody>
                    {% for tag in popular_tags %}
                    <tr>
                        <td><a href="{% url 'admin:taggit_tag_change' tag.pk %}">{{ tag.name }}</a></td>
                        <td>{{ tag.usage_count }}</td>
                    </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
    
    {{ block.super }}
{% endblock %}

Permissions and Security

Managing permissions for tag administration.

from django.contrib import admin
from django.contrib.auth.decorators import permission_required

class SecureTagAdmin(admin.ModelAdmin):
    def has_delete_permission(self, request, obj=None):
        """Restrict tag deletion to superusers."""
        return request.user.is_superuser
    
    def has_change_permission(self, request, obj=None):
        """Allow tag editing for users with change permission."""
        return request.user.has_perm('taggit.change_tag')
    
    def get_queryset(self, request):
        """Filter tags based on user permissions."""
        qs = super().get_queryset(request)
        if not request.user.is_superuser:
            # Regular users can only see tags they've created
            # (requires custom Tag model with created_by field)
            pass
        return qs

# Custom permissions in models.py
class CustomTag(Tag):
    created_by = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    
    class Meta:
        permissions = [
            ('can_merge_tags', 'Can merge tags'),
            ('can_bulk_delete_tags', 'Can bulk delete tags'),
        ]

Install with Tessl CLI

npx tessl i tessl/pypi-django-taggit

docs

admin-interface.md

form-integration.md

index.md

model-integration.md

rest-framework.md

tag-operations.md

utilities-management.md

view-helpers.md

tile.json