Django 信号基于日期时间字段值



我正在为以下问题而苦苦挣扎。我正在尝试创建一个自定义信号,当当前时间等于我的模型notify_on DateTimeField值时,该信号将触发。

像这样:

class Notification(models.Model):
    ...
    notify_on = models.DateTimeField()

def send_email(*args, **kwargs):
    # send email

signals.when_its_time.connect(send_email, sender=User)

在我通读了所有文档之后,我没有发现有关如何实现这种信号的信息。

有什么想法吗?

更新:不那么幼稚的方法,能够丢弃不相关的任务:https://stackoverflow.com/a/55337663/9631956

好的,感谢@SergeyPugach的评论,我已经做了以下工作:

添加了一个post_save信号,该信号调用向芹菜添加任务的函数。 apply_async让你通过eta - 预计到达时间可以直接接受DateTimeField,这非常方便。

# models.py
from django.db.models import signals
from django.db import models
from .tasks import send_notification
class Notification(models.Model):
    ...
    notify_on = models.DateTimeField()

def notification_post_save(instance, *args, **kwargs):
    send_notification.apply_async((instance,), eta=instance.notify_on)

signals.post_save.connect(notification_post_save, sender=Notification)

以及tasks.py中的实际任务

import logging
from user_api.celery import app
from django.core.mail import send_mail
from django.template.loader import render_to_string

@app.task
def send_notification(self, instance):
    try:
        mail_subject = 'Your notification.'
        message = render_to_string('notify.html', {
            'title': instance.title,
            'content': instance.content
        })
        send_mail(mail_subject, message, recipient_list=[instance.user.email], from_email=None)
    except instance.DoesNotExist:
        logging.warning("Notification does not exist anymore")

我不会详细介绍设置芹菜,那里有很多信息。

现在,我将尝试弄清楚如何在更新通知实例后更新任务,但这是一个完全不同的故事。

在 django 的文档中,有两个有趣的信号可以帮助你完成这个任务:pre_save 和 post_save。这取决于您的需求,但假设您要在保存模型后(实际上是在调用 save()create() 方法之后(检查模型的notify_on是否等于当前日期。如果是您的情况,您可以执行以下操作:

from datetime import datetime
from django.contrib.auth.models import User
from django.db import models
from django.dispatch import receiver
from django.db.models.signals import post_save

class Notification(models.Model):
    ...
    # Every notification is related to a user
    # It depends on your model, but i guess you're doing something similar
    user = models.ForeignKey(User, related_name='notify', on_delete=models.DO_NOTHING)
    notify_on = models.DateTimeField()
    ...
    def send_email(self, *args, **kwargs):
        """A model method to send email notification"""
        ...

@receiver(post_save, sender=User)
def create_notification(sender, instance, created, **kwargs):
    # check if the user instance is created
    if created:
        obj = Notification.objects.create(user=instance, date=datetime.now().date())
        if obj.notify_on == datetime.now().date():
            obj.send_email()

你应该知道,django 信号只有在有一个触发它们的行为时才会起作用。这意味着 Django 信号不会遍历模型的实例并执行操作,但 django 信号会在应用程序对连接到信号的模型执行操作时触发。

奖励:要对您的实例执行循环并定期处理操作,您可能需要一个具有Queue数据库的 async 工作线程(大多数情况下,Celery具有 Redis or RabbitMQ (。

相关内容

  • 没有找到相关文章

最新更新