Skip to main content
 首页 » 编程设计

python之Django:标记为已读 "Notifications"

2024年08月19日36Leo_wl

我正在做一个学校项目。现在任何用户都可以提出问题。

为了在任何用户提出问题时通知所有用户,我创建了一个新应用程序并在提出问题时通过简单的“ View ”通知他们。但这只是普通的通知。

一旦用户打开“通知”选项卡,我如何将它们标记为已读?就像在社交网络上一样!

请您参考如下方法:

我建议你使用ContentType为任何模型制作动态通知。下面的代码片段是如何实现通知系统的示例;

<强> 1。在你的 models.py

from django.db import models 
from django.contrib.auth.models import User 
from django.contrib.contenttypes.models import ContentType 
from django.contrib.contenttypes.fields import GenericForeignKey 
from django.utils.translation import ugettext_lazy as _ 
 
 
class ContentTypeToGetModel(object): 
 
    """ 
    requires fields: 
        - content_type: FK(ContentType) 
        - object_id: PositiveIntegerField() 
    """ 
 
    def get_related_object(self): 
        """ 
        return the related object of content_type. 
        eg: <Question: Holisticly grow synergistic best practices> 
        """ 
        # This should return an error: MultipleObjectsReturned 
        # return self.content_type.get_object_for_this_type() 
        # So, i handle it with this one: 
        model_class = self.content_type.model_class() 
        return model_class.objects.get(id=self.object_id) 
 
    @property 
    def _model_name(self): 
        """ 
        return lowercase of model name. 
        eg: `question`, `answer` 
        """ 
        return self.get_related_object()._meta.model_name 
 
 
class Notification(models.Model, ContentTypeToGetModel): 
    # sender = models.ForeignKey( 
    #    User, related_name='notification_sender') 
 
    receiver = models.ForeignKey( 
        User, related_name='notification_receiver') 
 
    content_type = models.ForeignKey( 
        ContentType, related_name='notifications', on_delete=models.CASCADE) 
 
    object_id = models.PositiveIntegerField(_('Object id')) 
    content_object = GenericForeignKey('content_type', 'object_id') 
 
    created = models.DateTimeField(auto_now_add=True) 
    modified = models.DateTimeField(auto_now=True) 
 
    STATUS_CHOICES = ( 
        ('reply', _('a reply')), 
        ('comment', _('a comment')), 
        ('message', _('a message')) 
    ) 
    status = models.CharField( 
        _('Status'), max_length=20, 
        choices=STATUS_CHOICES, default='comment') 
 
    is_read = models.BooleanField( 
        _('Is read?'), default=False) 
 
    def __str__(self): 
        title = _('%(receiver)s have a %(status)s in the %(model)s:%(id)s') 
        return title % {'receiver': self.receiver.username, 'status': self.status, 
                        'model': self._model_name, 'id': self.object_id} 
 
    class Meta: 
        verbose_name_plural = _('notifications') 
        ordering = ['-created'] 

<强> 2。在你的 views.py

from django.views.generic import (ListView, DetailView) 
from yourapp.models import Notification 
 
 
class NotificationListView(ListView): 
    model = Notification 
    context_object_name = 'notifications' 
    paginate_by = 10 
    template_name = 'yourapp/notifications.html' 
 
    def get_queryset(self): 
        notifications = self.model.objects.filter(receiver=self.request.user) 
 
        # mark as reads if `user` is visit on this page. 
        notifications.update(is_read=True) 
        return notifications 

<强> 3。在你的 yourapp/notifications.html

{% extends "base.html" %} 
 
{% for notif in notifications %} 
  {{ notif }} 
 
  {# for specific is like below #} 
  {# `specific_model_name` eg: `comment`, `message`, `post` #} 
  {% if notif._model_name == 'specific_model_name' %} 
    {# do_stuff #} 
  {% endif %} 
{% endfor %} 

So, when I creat that notifications? eg: when the other user send a comment to receiver on this post.

from django.contrib.contenttypes.models import ContentType 
 
def send_a_comment(request): 
    if request.method == 'POST': 
        form = SendCommentForm(request.POST) 
        if form.is_valid(): 
            instance = form.save(commit=False) 
            #instance.sender = request.user 
            ... 
            instance.save() 
 
            receiver = User.objects.filter(email=instance.email).first() 
            content_type = ContentType.objects.get(model='comment') 
 
            notif = Notification.objects.create( 
                receiver=receiver, 
                #sender=request.user, 
                content_type=content_type, 
                object_id=instance.id, 
                status='comment' 
            ) 
            notif.save() 

How about menu? Like this stackoverflow, facebook, instagram, or else?

您可以使用模板标签来处理它,例如:

# yourapp/templatetags/notification_tags.py 
 
from django import template 
 
from yourapp.models import Notification 
 
register = template.Library() 
 
@register.filter 
def has_unread_notif(user): 
    notifications = Notification.objects.filter(receiver=user, is_read=False) 
    if notifications.exists(): 
        return True 
    return False 

和 navs.html 菜单:

{% load notification_tags %} 
 
{% if request.user.is_authenticated %} 
  <ul class="authenticated-menu"> 
    <li> 
        <a href="/notifications/"> 
          {% if request.user|has_unread_notif %} 
            <i class="globe red active icon"></i> 
          {% else %} 
            <i class="globe icon"></i> 
          {% endif %} 
        </a> 
    </li> 
  </ul> 
{% endif %}