CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-django-notifications-hq

GitHub notifications alike app for Django providing comprehensive activity tracking and notification features.

Pending
Overview
Eval results
Files

admin-integration.mddocs/

Admin Integration

Admin interface configuration for managing notifications with proper field displays, filtering options, and bulk actions for administrative oversight and debugging.

Capabilities

Notification Admin Classes

Django admin configuration classes for managing notifications in the Django admin interface.

class AbstractNotificationAdmin(admin.ModelAdmin):
    """Base admin class for notification models."""
    raw_id_fields = ('recipient',)
    list_display = ('recipient', 'actor', 'level', 'target', 'unread', 'public')
    list_filter = ('level', 'unread', 'public', 'timestamp')
    
    def get_queryset(self, request):
        """
        Optimize queryset with prefetch_related for better performance.
        
        Args:
            request: Django admin request object
            
        Returns:
            QuerySet: Optimized queryset with prefetched actors
        """

class NotificationAdmin(AbstractNotificationAdmin):
    """Concrete admin class for Notification model."""
    raw_id_fields = ('recipient',)
    readonly_fields = ('action_object_url', 'actor_object_url', 'target_object_url')
    list_display = ('recipient', 'actor', 'level', 'target', 'unread', 'public')
    list_filter = ('level', 'unread', 'public', 'timestamp')
    actions = [mark_unread]
    
    def get_queryset(self, request):
        """
        Get optimized queryset for admin display.
        
        Args:
            request: Django admin request object
            
        Returns:
            QuerySet: Notifications with prefetched related objects
        """

Admin Actions

Custom admin actions for bulk operations on notifications.

def mark_unread(modeladmin, request, queryset):
    """
    Admin action to mark selected notifications as unread.
    
    Args:
        modeladmin: Admin model instance
        request: Django admin request object  
        queryset: Selected notification objects
        
    Returns:
        None: Updates notifications in place
        
    Description:
        Bulk action that sets unread=True for selected notifications
    """

Usage Examples

Custom Admin Configuration

# In your admin.py
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from notifications.models import Notification
from notifications.admin import NotificationAdmin as BaseNotificationAdmin

# Extend the base admin class
class CustomNotificationAdmin(BaseNotificationAdmin):
    # Add more fields to list display
    list_display = (
        'recipient', 
        'actor', 
        'verb',
        'level', 
        'target', 
        'unread', 
        'public',
        'timestamp',
        'get_description_preview'
    )
    
    # Add more filter options
    list_filter = (
        'level', 
        'unread', 
        'public', 
        'timestamp',
        'deleted',
        'emailed'
    )
    
    # Enable search
    search_fields = (
        'recipient__username',
        'recipient__email', 
        'verb',
        'description'
    )
    
    # Add readonly fields
    readonly_fields = (
        'action_object_url', 
        'actor_object_url', 
        'target_object_url',
        'timestamp',
        'slug'
    )
    
    # Organize fields in fieldsets
    fieldsets = (
        ('Basic Information', {
            'fields': ('recipient', 'level', 'unread', 'public')
        }),
        ('Activity Details', {
            'fields': ('actor_content_type', 'actor_object_id', 'verb', 'description')
        }),
        ('Related Objects', {
            'fields': ('target_content_type', 'target_object_id', 'action_object_content_type', 'action_object_object_id'),
            'classes': ('collapse',)
        }),
        ('Metadata', {
            'fields': ('timestamp', 'deleted', 'emailed', 'data'),
            'classes': ('collapse',)
        }),
        ('Admin Links', {
            'fields': ('actor_object_url', 'target_object_url', 'action_object_url'),
            'classes': ('collapse',)
        })
    )
    
    # Custom methods for display
    def get_description_preview(self, obj):
        """Show truncated description in list view."""
        if obj.description:
            return obj.description[:50] + '...' if len(obj.description) > 50 else obj.description
        return '-'
    get_description_preview.short_description = 'Description'
    
    def get_actor_type(self, obj):
        """Show actor content type."""
        return obj.actor_content_type.model
    get_actor_type.short_description = 'Actor Type'
    
    # Add custom actions
    actions = ['mark_unread', 'mark_read', 'soft_delete', 'mark_as_sent']
    
    def mark_read(self, request, queryset):
        """Mark selected notifications as read."""
        updated = queryset.update(unread=False)
        self.message_user(request, f'{updated} notifications marked as read.')
    mark_read.short_description = 'Mark selected notifications as read'
    
    def soft_delete(self, request, queryset):
        """Soft delete selected notifications."""
        updated = queryset.update(deleted=True)
        self.message_user(request, f'{updated} notifications soft deleted.')
    soft_delete.short_description = 'Soft delete selected notifications'
    
    def mark_as_sent(self, request, queryset):
        """Mark selected notifications as emailed."""
        updated = queryset.update(emailed=True)  
        self.message_user(request, f'{updated} notifications marked as sent.')
    mark_as_sent.short_description = 'Mark selected notifications as emailed'

# Unregister the default admin and register custom one
admin.site.unregister(Notification)
admin.site.register(Notification, CustomNotificationAdmin)

Read-Only Admin for Analytics

from django.contrib import admin
from notifications.models import Notification

class NotificationAnalyticsAdmin(admin.ModelAdmin):
    """Read-only admin for analytics and reporting."""
    
    list_display = (
        'id',
        'recipient',
        'actor', 
        'verb',
        'level',
        'timestamp',
        'unread',
        'get_time_since_created'
    )
    
    list_filter = (
        'level',
        'unread', 
        'public',
        'timestamp',
        ('timestamp', admin.DateFieldListFilter),
    )
    
    search_fields = ('recipient__username', 'verb', 'description')
    
    # Make it read-only
    def has_add_permission(self, request):
        return False
    
    def has_change_permission(self, request, obj=None):
        return False
    
    def has_delete_permission(self, request, obj=None):
        return False
    
    def get_time_since_created(self, obj):
        """Show time since notification was created."""
        return obj.timesince()
    get_time_since_created.short_description = 'Age'
    
    # Add date hierarchy for easy browsing
    date_hierarchy = 'timestamp'
    
    # Show more items per page
    list_per_page = 50

# Register as separate admin interface
admin.site.register(Notification, NotificationAnalyticsAdmin, name='notification_analytics')

Inline Admin for Related Models

from django.contrib import admin
from notifications.models import Notification

class NotificationInline(admin.TabularInline):
    """Inline admin for showing notifications on related models."""
    model = Notification
    extra = 0
    readonly_fields = ('timestamp', 'level', 'verb', 'unread')
    fields = ('timestamp', 'level', 'verb', 'unread', 'description')
    
    def has_add_permission(self, request, obj=None):
        return False

# Add to User admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User

class UserAdmin(BaseUserAdmin):
    inlines = [NotificationInline]

admin.site.unregister(User)
admin.site.register(User, UserAdmin)

Advanced Filtering

from django.contrib import admin
from django.utils.translation import gettext_lazy as _

class UnreadFilter(admin.SimpleListFilter):
    """Custom filter for unread status."""
    title = _('read status')
    parameter_name = 'read_status'
    
    def lookups(self, request, model_admin):
        return (
            ('unread', _('Unread')),
            ('read', _('Read')),
            ('recent_unread', _('Unread (last 7 days)')),
        )
    
    def queryset(self, request, queryset):
        if self.value() == 'unread':
            return queryset.filter(unread=True)
        elif self.value() == 'read':
            return queryset.filter(unread=False)
        elif self.value() == 'recent_unread':
            from django.utils import timezone
            from datetime import timedelta
            week_ago = timezone.now() - timedelta(days=7)
            return queryset.filter(unread=True, timestamp__gte=week_ago)

class ActorTypeFilter(admin.SimpleListFilter):
    """Filter by actor model type."""
    title = _('actor type')
    parameter_name = 'actor_type'
    
    def lookups(self, request, model_admin):
        # Get unique actor content types
        from django.contrib.contenttypes.models import ContentType
        actor_types = Notification.objects.values_list(
            'actor_content_type', flat=True
        ).distinct()
        
        return [
            (ct_id, ContentType.objects.get(id=ct_id).model.title())
            for ct_id in actor_types
        ]
    
    def queryset(self, request, queryset):
        if self.value():
            return queryset.filter(actor_content_type=self.value())

class CustomNotificationAdmin(admin.ModelAdmin):
    list_filter = (
        UnreadFilter,
        ActorTypeFilter,
        'level',
        'public',
        'timestamp'
    )

Bulk Data Management

from django.contrib import admin
from django.http import HttpResponse
import csv

class NotificationDataAdmin(admin.ModelAdmin):
    """Admin with data export and bulk management features."""
    
    actions = [
        'export_as_csv',
        'bulk_mark_read',
        'bulk_soft_delete',
        'cleanup_old_notifications'
    ]
    
    def export_as_csv(self, request, queryset):
        """Export selected notifications as CSV."""
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename="notifications.csv"'
        
        writer = csv.writer(response)
        writer.writerow([
            'ID', 'Recipient', 'Actor', 'Verb', 'Level', 
            'Timestamp', 'Unread', 'Description'
        ])
        
        for notification in queryset:
            writer.writerow([
                notification.id,
                notification.recipient.username,
                str(notification.actor),
                notification.verb,
                notification.level,
                notification.timestamp,
                notification.unread,
                notification.description or ''
            ])
        
        return response
    export_as_csv.short_description = 'Export selected notifications as CSV'
    
    def bulk_mark_read(self, request, queryset):
        """Mark all selected notifications as read."""
        count = queryset.filter(unread=True).update(unread=False)
        self.message_user(request, f'{count} notifications marked as read.')
    bulk_mark_read.short_description = 'Mark selected as read'
    
    def bulk_soft_delete(self, request, queryset):
        """Soft delete selected notifications."""
        count = queryset.update(deleted=True)
        self.message_user(request, f'{count} notifications soft deleted.')
    bulk_soft_delete.short_description = 'Soft delete selected'
    
    def cleanup_old_notifications(self, request, queryset):
        """Delete notifications older than 30 days."""
        from django.utils import timezone
        from datetime import timedelta
        
        cutoff_date = timezone.now() - timedelta(days=30)
        old_notifications = queryset.filter(timestamp__lt=cutoff_date)
        count = old_notifications.count()
        old_notifications.delete()
        
        self.message_user(request, f'{count} old notifications deleted.')
    cleanup_old_notifications.short_description = 'Delete notifications older than 30 days'

Permission-Based Admin

from django.contrib import admin

class PermissionBasedNotificationAdmin(admin.ModelAdmin):
    """Admin with permission-based access control."""
    
    def get_queryset(self, request):
        """Filter notifications based on user permissions."""
        qs = super().get_queryset(request)
        
        if request.user.is_superuser:
            return qs
        elif request.user.has_perm('notifications.view_all_notifications'):
            return qs
        else:
            # Only show notifications for users the admin can manage
            managed_users = self.get_managed_users(request.user)
            return qs.filter(recipient__in=managed_users)
    
    def get_managed_users(self, admin_user):
        """Get users this admin can manage."""
        # Example: staff can manage users in their department
        if hasattr(admin_user, 'department'):
            return admin_user.department.users.all()
        return []
    
    def has_change_permission(self, request, obj=None):
        """Check if user can change specific notification."""
        if not super().has_change_permission(request, obj):
            return False
        
        if obj and not request.user.is_superuser:
            # Check if admin can manage this notification's recipient
            managed_users = self.get_managed_users(request.user)
            return obj.recipient in managed_users
        
        return True

Integration with Custom Models

from django.contrib import admin
from myapp.models import BlogPost
from notifications.models import Notification

class BlogPostAdmin(admin.ModelAdmin):
    """Blog post admin with notification management."""
    
    def save_model(self, request, obj, form, change):
        """Send notification when blog post is published."""
        super().save_model(request, obj, form, change)
        
        if not change and obj.status == 'published':
            # Send notification to followers
            from notifications.signals import notify
            followers = obj.author.followers.all()
            
            notify.send(
                sender=obj.author,
                recipient=followers,
                verb='published new post',
                target=obj,
                description=f'New blog post: {obj.title}'
            )
            
            self.message_user(
                request, 
                f'Post published and {followers.count()} followers notified.'
            )
    
    def get_notification_count(self, obj):
        """Show notification count for this post."""
        return Notification.objects.filter(
            target_content_type__model='blogpost',
            target_object_id=obj.id
        ).count()
    get_notification_count.short_description = 'Notifications'

admin.site.register(BlogPost, BlogPostAdmin)

Install with Tessl CLI

npx tessl i tessl/pypi-django-notifications-hq

docs

admin-integration.md

api-endpoints.md

configuration.md

core-system.md

index.md

signals.md

template-integration.md

utilities.md

web-interface.md

tile.json