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

template-integration.mddocs/

Template Integration

Django template tags for displaying notification counts, status indicators, and live-updating notification interfaces with JavaScript integration for real-time updates.

Capabilities

Template Tags

Django template tags for displaying notification information and generating JavaScript for live updates.

@register.simple_tag(takes_context=True)
def notifications_unread(context):
    """
    Get unread notification count for current user (cached).
    
    Args:
        context: Django template context containing request and user
        
    Returns:
        int: Number of unread notifications for authenticated user, 0 for anonymous
        
    Template usage:
        {% notifications_unread %}
        {% notifications_unread as count %}
    """

@register.filter
def has_notification(user):
    """
    Check if user has any unread notifications.
    
    Args:
        user: Django User object
        
    Returns:
        bool: True if user has unread notifications, False otherwise
        
    Template usage:
        {{ user|has_notification }}
        {% if user|has_notification %}...{% endif %}
    """

@register.simple_tag
def register_notify_callbacks(
    badge_class='live_notify_badge',
    menu_class='live_notify_list', 
    refresh_period=15,
    callbacks='',
    api_name='list',
    fetch=5,
    nonce=None,
    mark_as_read=False
):
    """
    Generate JavaScript code for live notification functionality.
    
    Args:
        badge_class (str): CSS class for notification badge elements
        menu_class (str): CSS class for notification list elements  
        refresh_period (int): Update interval in seconds
        callbacks (str): Comma-separated callback function names
        api_name (str): API endpoint type ('list' or 'count')
        fetch (int): Number of notifications to fetch
        nonce (str, optional): CSP nonce for script tag
        mark_as_read (bool): Auto-mark notifications as read when fetched
        
    Returns:
        str: HTML script tag with JavaScript configuration
        
    Template usage:
        {% register_notify_callbacks %}
        {% register_notify_callbacks refresh_period=30 fetch=10 %}
    """

@register.simple_tag(takes_context=True)
def live_notify_badge(context, badge_class='live_notify_badge'):
    """
    Render live notification count badge.
    
    Args:
        context: Django template context
        badge_class (str): CSS class for badge element
        
    Returns:
        str: HTML span element with current unread count
        
    Template usage:
        {% live_notify_badge %}
        {% live_notify_badge "my-badge-class" %}
    """

@register.simple_tag  
def live_notify_list(list_class='live_notify_list'):
    """
    Render empty notification list container for JavaScript population.
    
    Args:
        list_class (str): CSS class for list container
        
    Returns:
        str: Empty HTML ul element for notifications
        
    Template usage:
        {% live_notify_list %}
        {% live_notify_list "my-list-class" %}
    """

Caching Function

def get_cached_notification_unread_count(user):
    """
    Get cached unread notification count for user.
    
    Args:
        user: Django User object
        
    Returns:
        int: Cached unread notification count
        
    Note:
        Uses Django cache with CACHE_TIMEOUT setting for cache duration
    """

Usage Examples

Basic Template Integration

<!-- Load the template tags -->
{% load notifications_tags %}

<!-- Simple unread count display -->
<div class="notifications">
    Notifications ({% notifications_unread %})
</div>

<!-- Store count in variable -->
{% notifications_unread as unread_count %}
{% if unread_count > 0 %}
    <div class="notification-alert">
        You have {{ unread_count }} unread notification{{ unread_count|pluralize }}
    </div>
{% endif %}

<!-- Check if user has notifications -->
{% if user|has_notification %}
    <span class="notification-indicator">●</span>
{% endif %}

Navigation Bar Integration

{% load notifications_tags %}

<nav class="navbar">
    <ul class="nav-items">
        <li class="nav-item">
            <a href="{% url 'notifications:unread' %}" class="nav-link">
                <i class="icon-bell"></i>
                Notifications
                {% notifications_unread as count %}
                {% if count > 0 %}
                    <span class="badge badge-danger">{{ count }}</span>
                {% endif %}
            </a>
        </li>
    </ul>
</nav>

<!-- Dropdown notification menu -->
<div class="notification-dropdown">
    <button class="dropdown-toggle" data-toggle="dropdown">
        <i class="icon-bell"></i>
        {% if user|has_notification %}
            <span class="notification-dot"></span>
        {% endif %}
    </button>
    <div class="dropdown-menu">
        <div class="dropdown-header">
            Notifications
            <span class="count">{% notifications_unread %}</span>
        </div>
        <div class="notification-list" id="notification-dropdown-list">
            <!-- Will be populated by JavaScript -->
        </div>
        <div class="dropdown-footer">
            <a href="{% url 'notifications:all' %}">View All</a>
            <a href="{% url 'notifications:mark_all_as_read' %}">Mark All as Read</a>
        </div>
    </div>
</div>

Live Notification Setup

{% load notifications_tags %}

<!DOCTYPE html>
<html>
<head>
    <title>My App</title>
    <style>
        .live_notify_badge {
            background: red;
            color: white;
            border-radius: 50%;
            padding: 2px 6px;
            font-size: 12px;
            position: absolute;
            top: -8px;
            right: -8px;
        }
        
        .live_notify_list {
            max-height: 300px;
            overflow-y: auto;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        
        .notification-item {
            padding: 10px;
            border-bottom: 1px solid #eee;
            cursor: pointer;
        }
        
        .notification-item:hover {
            background-color: #f5f5f5;
        }
    </style>
</head>
<body>
    <div class="header">
        <div class="notification-container" style="position: relative;">
            <i class="icon-bell"></i>
            <!-- Live badge that updates automatically -->
            {% live_notify_badge %}
        </div>
    </div>
    
    <div class="notification-panel">
        <h3>Recent Notifications</h3>
        <!-- Live list that updates automatically -->
        {% live_notify_list %}
    </div>
    
    <!-- Register JavaScript for live updates -->
    {% register_notify_callbacks refresh_period=20 fetch=8 %}
    
    <!-- Custom callback functions -->
    <script>
        function onNotificationUpdate(data) {
            console.log('Notifications updated:', data);
            // Custom handling when notifications are updated
            if (data.unread_count > 0) {
                document.title = `(${data.unread_count}) My App`;
            } else {
                document.title = 'My App';
            }
        }
        
        function onNotificationClick(notification) {
            console.log('Notification clicked:', notification);
            // Handle notification click
            window.location.href = '/notification/' + notification.id;
        }
    </script>
    
    <!-- Register callbacks -->
    {% register_notify_callbacks callbacks="onNotificationUpdate,onNotificationClick" %}
</body>
</html>

Advanced Configuration

{% load notifications_tags %}

<!-- Custom CSS classes and configuration -->
{% register_notify_callbacks 
    badge_class="my-notification-badge"
    menu_class="my-notification-menu"
    refresh_period=30
    api_name="list"
    fetch=15
    mark_as_read=True
%}

<!-- Multiple notification areas -->
<div class="sidebar">
    <h4>Quick Notifications</h4>
    {% live_notify_list "sidebar-notifications" %}
</div>

<div class="main-content">
    <div class="toolbar">
        <span class="notification-icon">
            🔔
            {% live_notify_badge "toolbar-badge" %}
        </span>
    </div>
</div>

<!-- Configure different areas with different settings -->
<script>
    // Custom configuration for sidebar
    {% register_notify_callbacks 
        menu_class="sidebar-notifications"
        fetch=5
        refresh_period=60
    %}
    
    // Custom configuration for toolbar
    {% register_notify_callbacks 
        badge_class="toolbar-badge"
        api_name="count"
        refresh_period=15
    %}
</script>

CSP (Content Security Policy) Support

{% load notifications_tags %}

<!-- Generate nonce for CSP -->
{% csrf_token %}
<script nonce="{{ csp_nonce }}">
    const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
</script>

<!-- Pass nonce to template tag -->
{% register_notify_callbacks nonce=csp_nonce %}

Conditional Loading

{% load notifications_tags %}

<!-- Only load live notifications for authenticated users -->
{% if user.is_authenticated %}
    <div class="user-notifications">
        {% if user|has_notification %}
            <div class="notification-alert">
                You have new notifications!
                {% live_notify_badge %}
            </div>
        {% endif %}
        
        {% live_notify_list %}
        {% register_notify_callbacks %}
    </div>
{% else %}
    <div class="guest-message">
        <a href="{% url 'login' %}">Login</a> to see notifications
    </div>
{% endif %}

Integration with Bootstrap

{% load notifications_tags %}

<!-- Bootstrap navbar with notification dropdown -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <div class="navbar-nav ms-auto">
        <div class="nav-item dropdown">
            <a class="nav-link dropdown-toggle position-relative" href="#" data-bs-toggle="dropdown">
                <i class="fas fa-bell"></i>
                {% live_notify_badge "position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger" %}
            </a>
            <div class="dropdown-menu dropdown-menu-end" style="width: 300px;">
                <h6 class="dropdown-header">
                    Notifications
                    <span class="badge bg-primary ms-2">{% notifications_unread %}</span>
                </h6>
                <div class="dropdown-divider"></div>
                <div class="notification-container" style="max-height: 400px; overflow-y: auto;">
                    {% live_notify_list "list-unstyled" %}
                </div>
                <div class="dropdown-divider"></div>
                <div class="dropdown-item-text text-center">
                    <a href="{% url 'notifications:all' %}" class="btn btn-sm btn-outline-primary me-2">
                        View All
                    </a>
                    <a href="{% url 'notifications:mark_all_as_read' %}" class="btn btn-sm btn-outline-secondary">
                        Mark All Read
                    </a>
                </div>
            </div>
        </div>
    </div>
</nav>

<!-- Bootstrap styling for notifications -->
<style>
    .list-unstyled .notification-item {
        padding: 0.5rem 1rem;
        border-bottom: 1px solid #dee2e6;
        text-decoration: none;
        color: inherit;
        display: block;
    }
    
    .list-unstyled .notification-item:hover {
        background-color: #f8f9fa;
    }
    
    .list-unstyled .notification-item:last-child {
        border-bottom: none;
    }
</style>

{% register_notify_callbacks 
    menu_class="list-unstyled"
    badge_class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger"
    refresh_period=25
    fetch=10
%}

Custom Notification Rendering

{% load notifications_tags %}

<!-- Override default notification rendering -->
<script>
function customNotificationRenderer(notifications) {
    const container = document.querySelector('.live_notify_list');
    container.innerHTML = '';
    
    notifications.forEach(notification => {
        const item = document.createElement('div');
        item.className = 'notification-item';
        item.innerHTML = `
            <div class="notification-avatar">
                <img src="/static/img/avatar-placeholder.png" alt="Avatar">
            </div>
            <div class="notification-content">
                <div class="notification-text">
                    <strong>${notification.actor}</strong> ${notification.verb}
                    ${notification.target ? notification.target : ''}
                </div>
                <div class="notification-time">
                    ${formatTimeAgo(notification.timestamp)}
                </div>
            </div>
            <div class="notification-actions">
                <button onclick="markAsRead(${notification.slug})" class="btn-sm">✓</button>
                <button onclick="deleteNotification(${notification.slug})" class="btn-sm">✗</button>
            </div>
        `;
        container.appendChild(item);
    });
}

// Override the default render function
window.renderNotifications = customNotificationRenderer;
</script>

{% live_notify_list %}
{% register_notify_callbacks callbacks="customNotificationRenderer" %}

Helper Functions

Internal helper functions used by template tags for user context handling and caching.

def get_cached_notification_unread_count(user):
    """
    Get cached unread notification count for user with configurable timeout.
    
    Args:
        user: Django User object
        
    Returns:
        int: Number of unread notifications (cached result)
        
    Cache key: 'cache_notification_unread_count'
    Cache timeout: Configured via CACHE_TIMEOUT setting
    """

def user_context(context):
    """
    Extract authenticated user from template context.
    
    Args:
        context: Django template context dict
        
    Returns:
        User: Authenticated user object or None for anonymous/missing users
        
    Handles:
        - Missing user in context
        - Anonymous users (both Django < 1.11 and >= 1.11 syntax)
        - Authenticated users
    """

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