简体   繁体   English

将 If 语句添加到无法正常工作的信号

[英]Adding If statement to signals not working properly

I have set a Notification system for my Django project whenever a user likes or comments on a post the Author receives a notification about this activity.每当用户喜欢或评论作者收到有关此活动的通知的帖子时,我都会为我的 Django 项目设置通知系统。

I have read about the Signals in django: https://docs.djangoproject.com/en/3.1/topics/signals/#listening-to-signals我已经阅读了 django 中的信号: https : //docs.djangoproject.com/en/3.1/topics/signals/#listening-to-signals

In the Post Model, I have added a num_likes which reflects the number of likes the post has received.在帖子模型中,我添加了一个num_likes ,它反映了帖子收到的点num_likes数。

I am trying to add an option so that the Author of the Post can receive a Notification when the num_likes reaches a certain number.我正在尝试添加一个选项,以便当num_likes达到某个数字时,帖子的作者可以收到通知。 In my example, it is the First Like.在我的例子中,它是第一个赞。

So, here is what I have tried but nothing happened.所以,这是我尝试过的,但什么也没发生。

Here is the models.py这是models.py

class Post(models.Model):
    title = models.CharField(max_length=100, unique=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author')
    num_likes = models.IntegerField(default=0, verbose_name='No. of Likes')
    likes = models.ManyToManyField(User, related_name='liked', blank=True)

    def __str__(self):
        return self.title
#---------------------------My trial------------------------------------------
    def like_progress(sender, instance, *args, **kwargs):
        post = instance
        if post.num_likes == 1:
            notify = Notification(post=post, user=post.author, notification_type=3)
            notify.save()

# num_likes
post_save.connect(Post.like_progress, sender=Post)
#---------------------------My trial------------------------------------------

Here are the notifications model.py这是通知 model.py

class Notification(models.Model):
    NOTIFICATION_TYPES=((1,'Like'),(2,'Comment'),(3,'Admin'))

    post = models.ForeignKey('blog.Post', on_delete=models.CASCADE, related_name="noti_post", blank=True, null=True)
    sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name="noti_from_user")
    user = models.ForeignKey(User, on_delete=models.CASCADE,related_name="noti_to_user")
    notification_type= models.IntegerField(choices=NOTIFICATION_TYPES)
    text_preview= models.CharField(max_length=90,blank=True)
    date=models.DateTimeField(auto_now=True)
    is_seen=models.BooleanField(default=False)

    def __str__(self):
        return self.notification_type

here are the notifications app views.py这是通知应用程序 views.py

def ShowNotifications(request, *args, **kwargs):
    user=request.user
    notifications= Notification.objects.filter(user=user).order_by('-date')
    Notification.objects.filter(user=user, is_seen=False).update(is_seen=True)

    template= loader.get_template('notifications/notifications.html')

    context = {
        'notifications': notifications,
    }

    return HttpResponse(template.render(context, request))

here is the url.py这是 url.py

app_name = 'notifications'

urlpatterns = [
    path('', ShowNotifications, name='show-notifications'),

here is the template:这是模板:

<!-- Admin Notification -->
{% if notification.notification_type == 3 %}
Your First Like in this post
{% endif %}
<!-- Admin Notification -->

So to summarize:所以总结一下:

I have a perfectly working Notification system I am just trying to add to it an option to notify the Author of a Post that he received a first like for example.我有一个完美运行的通知系统,我只是想在其中添加一个选项,以通知帖子的Author他收到了第一个赞。 What am I doing wrong in the above and how can I get this feature to work?我在上面做错了什么,我怎样才能让这个功能工作?

If there is anything vague or more information required please ask如果有任何模糊或需要更多信息,请询问

You don't receive the notification because of these two lines in your view:由于您的视图中有这两行,您没有收到通知:

notifications= Notification.objects.filter(user=user).order_by('-date')
Notification.objects.filter(user=user, is_seen=False).update(is_seen=True)

Let me explain what happens in those lines.让我解释一下这些行中发生了什么。

  1. You filter the notifications but the filter ORM method is lazy, which means it will not be executed until the objects are needed, which in your case is in the template您过滤通知,但过滤器 ORM 方法是惰性的,这意味着它不会在需要对象之前执行,在您的情况下是在模板中
  2. You then update the status of the notifications.然后更新通知的状态。 Unlike filter, update is not lazy so the query is immediately executed and the notifications have status is_seen as True in DB.与过滤器不同,更新不是惰性的,因此查询会立即执行,并且通知在 DB 中的状态为is_seen为 True。
  3. Django starts rendering your templates and executes the original filter to retrieve the notifications. Django 开始呈现您的模板并执行原始过滤器以检索通知。 At this point, you no longer have notifications with is_seen=False in the DB as you already updated them in step 2 to is_seen=True .此时,数据库中不再有is_seen=False通知,因为您已经在步骤 2 is_seen=True它们更新为is_seen=True So, the loop in the template that renders the notifications shows nothing as it could not find any unseen notifications in the DB.因此,呈现通知的模板中的循环没有显示任何内容,因为它在数据库中找不到任何看不见的通知。

To mitigate this, convert the notifications in step 1 to list, so that the query will be executed immediately.为了缓解这种情况,请将步骤 1 中的通知转换为列表,以便立即执行查询。 In this way, you are passing an actual list of objects to your template and not a lazy queryset.通过这种方式,您将一个实际的对象列表传递给您的模板,而不是一个惰性查询集。

This solves your problem:这可以解决您的问题:

notifications= list(Notification.objects.filter(user=user).order_by('-date'))

Converting it to list forces Django to immediately execute the query and return the objects将其转换为列表会强制 Django 立即执行查询并返回对象

Define like_progress in a new file, signals.py, in the same directory as .models.Post instead of in the model.在与.models.Post相同的目录中而不是在模型中的新文件like_progress中定义like_progress This will help avoid side effects.这将有助于避免副作用。

In practice, signal handlers are usually defined in a signals submodule of the application they relate to.在实践中,信号处理程序通常定义在与它们相关的应用程序的信号子模块中。

Register the signal handler in the appConfig for the app which contains the Post model, I called the app "blog", so the module path is blog.apps.BlogConfig and add that module path to INSTALLED_APPS , instead of just the app name.在 appConfig 中为包含Post模型的应用程序注册信号处理程序,我将应用程序称为“博客”,因此模块路径是blog.apps.BlogConfig并将该模块路径添加到INSTALLED_APPS ,而不仅仅是应用程序名称。

From the docs:从文档:

Signal receivers are connected in the ready() method of your application configuration class.信号接收器在应用程序配置类的 ready() 方法中连接。

And check out more information on the ready method .并查看有关 ready 方法的更多信息

Your apps.py file in the blog app (whereever Post model lives) should look like so:博客应用程序(无论Post模型所在的位置)中的 apps.py 文件应如下所示:

from django.apps import AppConfig
from django.db.models.signals import post_save


class BlogConfig(AppConfig):
    name = 'blog'

    def ready(self):
        from .models import Post
        from .signals import like_progress

        post_save.connect(like_progress, sender=Post)

Note that the imports need to happen in the ready method.请注意,导入需要在ready方法中进行。 There is also an option to specify the model import as a string.还有一个选项可以将模型导入指定为字符串。

Remember to also specify another user as a sender when you create the Notification.请记住,在创建通知时还要指定另一个用户作为发件人。 As in:如:

notify = Notification(post=post, user=post.author, sender=liker, notification_type=3)

And you might want to check out the docs on avoiding duplicate registration of signal handlers .您可能想查看有关避免重复注册信号处理程序的文档。

It's all in the docs you linked to, but it helped a lot to see what happened in the shell ( python manage.py shell ).这一切都在您链接到的文档中,但它有助于了解 shell ( python manage.py shell ) 中发生的情况。 At first it failed silently, but once the signal handler was moved into signals.py and registered in appConfig it started to show some results.起初它默默地失败了,但是一旦将信号处理程序移入signals.py 并在appConfig 中注册,它就开始显示一些结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM