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

core-system.mddocs/

Core Notification System

The foundational notification models, queryset methods, and signal handling that power the entire django-notifications-hq system. This includes the main Notification model with fields for actor, verb, target, timestamps, and read status.

Capabilities

Notification Model

The main notification model that extends AbstractNotification with additional humanization methods for displaying time information.

class Notification(AbstractNotification):
    def naturalday(self):
        """
        Return human-readable day format for notification timestamp.
        
        Returns:
            str: 'today', 'yesterday', or date string
        """
        
    def naturaltime(self):
        """
        Return human-readable relative time for notification timestamp.
        
        Returns:
            str: '2 hours ago', 'just now', etc.
        """
        
    class Meta(AbstractNotification.Meta):
        abstract = False
        swappable = swappable_setting('notifications', 'Notification')

Abstract Notification Model

The base notification model containing all core functionality for activity tracking with actor-verb-object patterns.

class AbstractNotification(models.Model):
    """
    Activity model describing actor acting out a verb on optional target.
    Based on Activity Streams specification.
    
    Format patterns:
    - <actor> <verb> <time>
    - <actor> <verb> <target> <time>  
    - <actor> <verb> <action_object> <target> <time>
    """
    
    # Core fields
    level = models.CharField(max_length=20, choices=LEVELS, default='info')
    recipient = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    unread = models.BooleanField(default=True, db_index=True)
    verb = models.CharField(max_length=255)
    description = models.TextField(blank=True, null=True)
    timestamp = models.DateTimeField(default=timezone.now, db_index=True)
    public = models.BooleanField(default=True, db_index=True)
    deleted = models.BooleanField(default=False, db_index=True)
    emailed = models.BooleanField(default=False, db_index=True)
    data = JSONField(blank=True, null=True)
    
    # Generic foreign key fields for actor
    actor_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    actor_object_id = models.CharField(max_length=255)
    actor = GenericForeignKey('actor_content_type', 'actor_object_id')
    
    # Generic foreign key fields for target (optional)
    target_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, blank=True, null=True)
    target_object_id = models.CharField(max_length=255, blank=True, null=True)
    target = GenericForeignKey('target_content_type', 'target_object_id')
    
    # Generic foreign key fields for action object (optional)
    action_object_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, blank=True, null=True)
    action_object_object_id = models.CharField(max_length=255, blank=True, null=True)
    action_object = GenericForeignKey('action_object_content_type', 'action_object_object_id')
    
    objects = NotificationQuerySet.as_manager()
    
    def __str__(self):
        """
        String representation following activity stream patterns.
        
        Returns:
            str: Formatted notification string with actor, verb, objects, and time
        """
        
    def timesince(self, now=None):
        """
        Time since notification creation using Django's timesince utility.
        
        Args:
            now (datetime, optional): Reference time for calculation
            
        Returns:
            str: Relative time string
        """
        
    @property
    def slug(self):
        """
        URL-safe slug for notification identification.
        
        Returns:
            int: Notification ID converted to URL slug
        """
        
    def mark_as_read(self):
        """Mark notification as read if currently unread."""
        
    def mark_as_unread(self):
        """Mark notification as unread if currently read."""
        
    def actor_object_url(self):
        """
        Generate admin URL for the actor object.
        
        Returns:
            str: HTML link to admin change page or plain ID
        """
        
    def action_object_url(self):
        """
        Generate admin URL for the action object.
        
        Returns:
            str: HTML link to admin change page or plain ID
        """
        
    def target_object_url(self):
        """
        Generate admin URL for the target object.
        
        Returns:
            str: HTML link to admin change page or plain ID
        """
        
    class Meta:
        abstract = True
        ordering = ('-timestamp',)
        index_together = ('recipient', 'unread')
        verbose_name = 'Notification'
        verbose_name_plural = 'Notifications'

Notification QuerySet

Custom queryset providing notification-specific filtering and bulk operations for efficient database queries and notification management.

class NotificationQuerySet(models.query.QuerySet):
    """Custom queryset with notification-specific methods."""
    
    def unsent(self):
        """
        Filter notifications that haven't been emailed.
        
        Returns:
            QuerySet: Notifications with emailed=False
        """
        
    def sent(self):
        """
        Filter notifications that have been emailed.
        
        Returns:
            QuerySet: Notifications with emailed=True
        """
        
    def unread(self, include_deleted=False):
        """
        Filter unread notifications.
        
        Args:
            include_deleted (bool): Whether to include soft-deleted notifications
            
        Returns:
            QuerySet: Unread notifications
        """
        
    def read(self, include_deleted=False):
        """
        Filter read notifications.
        
        Args:
            include_deleted (bool): Whether to include soft-deleted notifications
            
        Returns:
            QuerySet: Read notifications
        """
        
    def mark_all_as_read(self, recipient=None):
        """
        Mark all notifications in queryset as read.
        
        Args:
            recipient (User, optional): Filter by specific recipient
            
        Returns:
            int: Number of notifications updated
        """
        
    def mark_all_as_unread(self, recipient=None):
        """
        Mark all notifications in queryset as unread.
        
        Args:
            recipient (User, optional): Filter by specific recipient
            
        Returns:
            int: Number of notifications updated
        """
        
    def deleted(self):
        """
        Filter soft-deleted notifications.
        
        Returns:
            QuerySet: Notifications with deleted=True
            
        Raises:
            ImproperlyConfigured: If SOFT_DELETE setting is False
        """
        
    def active(self):
        """
        Filter active (non-deleted) notifications.
        
        Returns:
            QuerySet: Notifications with deleted=False
            
        Raises:
            ImproperlyConfigured: If SOFT_DELETE setting is False
        """
        
    def mark_all_as_deleted(self, recipient=None):
        """
        Soft delete all notifications in queryset.
        
        Args:
            recipient (User, optional): Filter by specific recipient
            
        Returns:
            int: Number of notifications updated
            
        Raises:
            ImproperlyConfigured: If SOFT_DELETE setting is False
        """
        
    def mark_all_as_active(self, recipient=None):
        """
        Restore all notifications in queryset from soft deletion.
        
        Args:
            recipient (User, optional): Filter by specific recipient
            
        Returns:
            int: Number of notifications updated
            
        Raises:
            ImproperlyConfigured: If SOFT_DELETE setting is False
        """
        
    def mark_as_unsent(self, recipient=None):
        """
        Mark notifications as not emailed.
        
        Args:
            recipient (User, optional): Filter by specific recipient
            
        Returns:
            int: Number of notifications updated
        """
        
    def mark_as_sent(self, recipient=None):
        """
        Mark notifications as emailed.
        
        Args:
            recipient (User, optional): Filter by specific recipient
            
        Returns:
            int: Number of notifications updated
        """

Notification Levels

LEVELS = Choices('success', 'info', 'warning', 'error')

Usage Examples

Creating and Querying Notifications

from django.contrib.auth.models import User
from notifications.models import Notification

# Get user notifications
user = User.objects.get(username='jane')

# Query unread notifications
unread = user.notifications.unread()

# Query read notifications  
read = user.notifications.read()

# Mark all as read
user.notifications.mark_all_as_read()

# Query by level
info_notifications = user.notifications.filter(level='info')

# Check if notification exists
has_unread = user.notifications.unread().exists()

# Get notification count
unread_count = user.notifications.unread().count()

# Access notification details
for notification in user.notifications.all()[:5]:
    print(f"{notification.actor} {notification.verb}")
    print(f"Time: {notification.naturaltime()}")
    print(f"Description: {notification.description}")
    if notification.target:
        print(f"Target: {notification.target}")

Individual Notification Management

# Get specific notification
notification = Notification.objects.get(id=123)

# Mark as read/unread
notification.mark_as_read()
notification.mark_as_unread()

# Access related objects
actor = notification.actor
target = notification.target
action_object = notification.action_object

# Get formatted time
time_ago = notification.timesince()
natural_day = notification.naturalday()

# Check properties
is_unread = notification.unread
is_public = notification.public
level = notification.level

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