CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-django-extensions

Django Extensions is a comprehensive collection of custom extensions that enhance the Django web framework with additional management commands, utilities, and developer tools.

Pending
Overview
Eval results
Files

admin-extensions.mddocs/

Admin Extensions

Django Extensions provides enhanced Django admin functionality including custom filters and widgets for improved administrative interfaces. These extensions integrate seamlessly with Django's admin system to provide better user experience and additional functionality.

Capabilities

Admin Filters

Custom filter classes that enhance Django admin list views with specialized filtering options.

class NullFieldListFilter(admin.SimpleListFilter):
    title: str = 'has value'
    parameter_name: str = 'has_value'
    
    def __init__(self, request, params, model, model_admin):
        """
        Admin filter for handling null/non-null field filtering.
        
        Provides filtering options for fields that can be null:
        - "Has value" (field is not null)
        - "No value" (field is null)
        
        Usage in ModelAdmin:
        list_filter = [('field_name', NullFieldListFilter)]
        """
    
    def lookups(self, request, model_admin):
        """
        Return filter options.
        
        Returns:
        - tuple: (('1', 'Has value'), ('0', 'No value'))
        """
    
    def queryset(self, request, queryset):
        """
        Filter the queryset based on selection.
        
        Parameters:
        - request: HttpRequest object
        - queryset: QuerySet to filter
        
        Returns:
        - QuerySet: Filtered queryset
        """

Usage examples:

from django.contrib import admin
from django_extensions.admin import NullFieldListFilter
from myapp.models import Article

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    list_display = ['title', 'author', 'published_date', 'featured_image']
    
    # Filter by fields that can be null
    list_filter = [
        ('published_date', NullFieldListFilter),
        ('featured_image', NullFieldListFilter),
        ('author', NullFieldListFilter),
    ]
    
    # Standard filters can be mixed with custom filters
    list_filter = [
        'category',  # Regular field filter
        ('published_date', NullFieldListFilter),  # Custom null filter
        'is_featured',  # Boolean field filter
    ]

# Custom implementation for specific fields
class CustomNullFilter(NullFieldListFilter):
    title = 'has thumbnail'
    parameter_name = 'has_thumbnail'

@admin.register(Photo)
class PhotoAdmin(admin.ModelAdmin):
    list_filter = [('thumbnail', CustomNullFilter)]

ForeignKey Autocomplete System

Complete system for ForeignKey autocomplete functionality including admin mixins, ModelAdmin classes, and inline classes.

class ForeignKeyAutocompleteAdminMixin:
    related_search_fields: dict[str, tuple[str, ...]]  # Field mapping to search fields
    related_string_functions: dict[str, Callable]  # Custom string representations
    autocomplete_limit: int | None  # Limit autocomplete results
    
    def __init__(self):
        """
        Admin mixin for models using the autocomplete feature.
        
        Configuration:
        - related_search_fields: Maps field names to searchable target fields
        - related_string_functions: Custom string representation functions
        - autocomplete_limit: Maximum number of results (default from settings)
        """
    
    def foreignkey_autocomplete(self, request):
        """
        AJAX endpoint for autocomplete search functionality.
        
        Parameters:
        - request: HttpRequest with query parameters (q, app_label, model_name, etc.)
        
        Returns:
        - HttpResponse: Text response with autocomplete results
        """
    
    def get_related_filter(self, model, request):
        """
        Hook for additional filtering in autocomplete queries.
        
        Parameters:
        - model: Model class being searched
        - request: Current HttpRequest
        
        Returns:
        - Q object or None: Additional filter for queryset
        """
    
    def get_help_text(self, field_name, model_name):
        """Generate help text for autocomplete fields."""

class ForeignKeyAutocompleteAdmin(ForeignKeyAutocompleteAdminMixin, admin.ModelAdmin):
    """ModelAdmin with ForeignKey autocomplete functionality."""

class ForeignKeyAutocompleteTabularInline(ForeignKeyAutocompleteAdminMixin, admin.TabularInline):
    """TabularInline with ForeignKey autocomplete functionality."""

class ForeignKeyAutocompleteStackedInline(ForeignKeyAutocompleteAdminMixin, admin.StackedInline):
    """StackedInline with ForeignKey autocomplete functionality."""

Usage examples:

from django.contrib import admin
from django_extensions.admin import ForeignKeyAutocompleteAdmin
from myapp.models import Article, Author, Category

class ArticleAdmin(ForeignKeyAutocompleteAdmin):
    # Configure autocomplete for specific fields
    related_search_fields = {
        'author': ('first_name', 'last_name', 'email'),
        'category': ('name', 'description'),
    }
    
    # Optional: Custom string representations
    related_string_functions = {
        'author': lambda obj: f"{obj.first_name} {obj.last_name} ({obj.email})",
    }
    
    # Optional: Limit autocomplete results
    autocomplete_limit = 20

admin.site.register(Article, ArticleAdmin)

# Using with inlines
class CommentInline(ForeignKeyAutocompleteTabularInline):
    model = Comment
    related_search_fields = {
        'author': ('username', 'email'),
    }

class ArticleWithCommentsAdmin(admin.ModelAdmin):
    inlines = [CommentInline]

Admin Widgets

Enhanced widgets for Django admin forms that improve user experience and provide additional functionality.

class ForeignKeySearchInput(widgets.Input):
    input_type: str = 'text'
    template_name: str = 'django_extensions/widgets/foreignkey_searchinput.html'
    
    def __init__(self, rel, admin_site, attrs=None, using=None):
        """
        Widget for displaying ForeignKeys in autocomplete search input.
        
        Provides enhanced foreign key selection with search functionality
        instead of dropdown menus for better performance with large datasets.
        
        Parameters:
        - rel: ForeignKey relationship
        - admin_site: AdminSite instance
        - attrs: HTML attributes for the widget
        - using: Database alias to use
        """
    
    def format_value(self, value):
        """
        Format the value for display in the input field.
        
        Parameters:
        - value: The foreign key value
        
        Returns:
        - str: Formatted value for display
        """
    
    def build_attrs(self, base_attrs, extra_attrs=None):
        """
        Build HTML attributes for the widget.
        
        Returns:
        - dict: HTML attributes dictionary
        """

Usage examples:

from django.contrib import admin
from django.db import models
from django_extensions.admin import ForeignKeySearchInput

class Article(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    category = models.ForeignKey('Category', on_delete=models.CASCADE)

class Category(models.Model):
    name = models.CharField(max_length=100)
    parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    # Use search input for foreign key fields
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name in ['author', 'category']:
            kwargs['widget'] = ForeignKeySearchInput(
                db_field.remote_field, 
                admin.site
            )
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

# Alternative: Custom form with search widgets
from django import forms

class ArticleAdminForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = '__all__'
        widgets = {
            'author': ForeignKeySearchInput(
                Article._meta.get_field('author').remote_field,
                admin.site
            ),
            'category': ForeignKeySearchInput(
                Article._meta.get_field('category').remote_field,
                admin.site
            ),
        }

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    form = ArticleAdminForm

Template Integration

The admin extensions include custom templates that integrate with Django's admin interface:

<!-- django_extensions/widgets/foreignkey_searchinput.html -->
<input type="{{ widget.type }}" 
       name="{{ widget.name }}"
       value="{{ widget.value|default:'' }}"
       {% if widget.attrs.id %} id="{{ widget.attrs.id }}"{% endif %}
       {% for name, value in widget.attrs.items %}
         {% if value is not False %} {{ name }}{% if value is not True %}="{{ value }}"{% endif %}{% endif %}
       {% endfor %}>

<!-- Include JavaScript for search functionality -->
<script type="text/javascript">
    // Enhanced search and autocomplete functionality
    // Integrates with Django admin's existing JavaScript
</script>

Advanced Admin Customization

from django.contrib import admin
from django.db import models
from django_extensions.admin import NullFieldListFilter, ForeignKeySearchInput

class BaseAdmin(admin.ModelAdmin):
    """Base admin class with common django-extensions functionality."""
    
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        # Use search input for all foreign key fields
        kwargs['widget'] = ForeignKeySearchInput(
            db_field.remote_field, 
            admin.site
        )
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

class TimestampedAdmin(BaseAdmin):
    """Admin for models with timestamp fields."""
    
    readonly_fields = ['created', 'modified']
    list_display = ['__str__', 'created', 'modified']
    list_filter = [
        ('created', admin.DateFieldListFilter),
        ('modified', admin.DateFieldListFilter),
    ]

class PublishableAdmin(BaseAdmin):
    """Admin for models with publication status."""
    
    list_display = ['title', 'is_published', 'publish_date']
    list_filter = [
        'is_published',
        ('publish_date', NullFieldListFilter),
        ('publish_date', admin.DateFieldListFilter),
    ]
    
    actions = ['mark_published', 'mark_unpublished']
    
    def mark_published(self, request, queryset):
        queryset.update(is_published=True)
    mark_published.short_description = "Mark selected items as published"
    
    def mark_unpublished(self, request, queryset):
        queryset.update(is_published=False)
    mark_unpublished.short_description = "Mark selected items as unpublished"

# Usage with django-extensions model base classes
from django_extensions.db.models import TimeStampedModel, TitleSlugDescriptionModel

class BlogPost(TimeStampedModel, TitleSlugDescriptionModel):
    content = models.TextField()
    author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    category = models.ForeignKey('Category', null=True, blank=True, on_delete=models.SET_NULL)
    is_published = models.BooleanField(default=False)
    publish_date = models.DateTimeField(null=True, blank=True)

@admin.register(BlogPost)
class BlogPostAdmin(TimestampedAdmin, PublishableAdmin):
    list_display = ['title', 'author', 'category', 'is_published', 'created']
    list_filter = [
        'is_published',
        ('author', NullFieldListFilter),
        ('category', NullFieldListFilter),
        ('publish_date', NullFieldListFilter),
        ('created', admin.DateFieldListFilter),
    ]
    search_fields = ['title', 'content', 'author__username']
    prepopulated_fields = {'slug': ('title',)}

Custom Filter Development

from django.contrib import admin
from django_extensions.admin import NullFieldListFilter

class CustomDateRangeFilter(admin.SimpleListFilter):
    """Custom filter extending NullFieldListFilter pattern."""
    
    title = 'date range'
    parameter_name = 'date_range'
    
    def lookups(self, request, model_admin):
        return (
            ('today', 'Today'),
            ('week', 'This Week'),
            ('month', 'This Month'),
            ('year', 'This Year'),
            ('no_date', 'No Date'),
        )
    
    def queryset(self, request, queryset):
        from django.utils import timezone
        from datetime import timedelta
        
        if self.value() == 'today':
            return queryset.filter(created__date=timezone.now().date())
        elif self.value() == 'week':
            week_ago = timezone.now() - timedelta(days=7)
            return queryset.filter(created__gte=week_ago)
        elif self.value() == 'month':
            month_ago = timezone.now() - timedelta(days=30)
            return queryset.filter(created__gte=month_ago)
        elif self.value() == 'year':
            year_ago = timezone.now() - timedelta(days=365)
            return queryset.filter(created__gte=year_ago)
        elif self.value() == 'no_date':
            return queryset.filter(created__isnull=True)
        return queryset

# Combined filtering approach
class AdvancedAdmin(admin.ModelAdmin):
    list_filter = [
        ('created', CustomDateRangeFilter),
        ('author', NullFieldListFilter),
        'status',
    ]

Widget Customization

from django_extensions.admin import ForeignKeySearchInput
from django.contrib import admin

class CustomSearchInput(ForeignKeySearchInput):
    """Customized foreign key search input with additional features."""
    
    template_name = 'myapp/widgets/custom_search_input.html'
    
    def build_attrs(self, base_attrs, extra_attrs=None):
        attrs = super().build_attrs(base_attrs, extra_attrs)
        attrs.update({
            'class': 'custom-search-input',
            'data-search-url': '/admin/api/search/',
            'placeholder': 'Type to search...'
        })
        return attrs

class EnhancedAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name in ['author', 'category']:
            kwargs['widget'] = CustomSearchInput(
                db_field.remote_field,
                admin.site,
                attrs={'class': 'enhanced-search'}
            )
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

Best Practices

# 1. Use null filters for optional relationships
class ArticleAdmin(admin.ModelAdmin):
    list_filter = [
        ('featured_image', NullFieldListFilter),  # Optional image
        ('publish_date', NullFieldListFilter),    # Optional publish date
        ('category', NullFieldListFilter),        # Optional category
    ]

# 2. Combine with search for large datasets
class UserAdmin(admin.ModelAdmin):
    search_fields = ['username', 'email', 'first_name', 'last_name']
    list_filter = [
        ('last_login', NullFieldListFilter),
        ('date_joined', admin.DateFieldListFilter),
    ]

# 3. Use search inputs for performance with large FK sets
class OrderAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        # Use search input for customer selection (many customers)
        if db_field.name == 'customer':
            kwargs['widget'] = ForeignKeySearchInput(
                db_field.remote_field, 
                admin.site
            )
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

# 4. Custom admin with multiple extensions
class ComprehensiveAdmin(admin.ModelAdmin):
    list_per_page = 50
    list_max_show_all = 200
    
    def get_list_filter(self, request):
        # Dynamic filter assignment
        filters = list(self.list_filter)
        
        # Add null filters for nullable foreign keys
        for field in self.model._meta.get_fields():
            if (field.is_relation and 
                getattr(field, 'null', False) and 
                hasattr(field, 'remote_field')):
                filters.append((field.name, NullFieldListFilter))
        
        return filters

Install with Tessl CLI

npx tessl i tessl/pypi-django-extensions

docs

admin-extensions.md

index.md

management-commands.md

model-base-classes.md

model-fields.md

template-tags.md

validators.md

tile.json