Django 基于日期时间字段值的信号
Django signal based on the datetime field value
我正在努力解决以下问题。
我正在尝试创建一个自定义信号,该信号将在当前时间等于我模型的 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)
在我通读了所有文档之后,我没有找到关于如何实现这种信号的信息。
有什么想法吗?
更新:
能够丢弃不相关任务的不那么天真的方法:
在 django 的文档中有两个有趣的信号可以帮助您完成此任务:pre_save and post_save。
这取决于您的需要,但假设您想在保存模型后检查模型的 notify_on
是否等于当前日期(实际上是在调用 save()
或 create()
方法之后)。如果是你的情况,你可以这样做:
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 信号会触发。
奖励:要对您的实例执行循环并定期处理操作,您可能需要 async
worker 和 Queue
数据库(主要是, Celery
与 Redis or RabbitMQ
).
好的,感谢@SergeyPugach 的评论,我完成了以下操作:
添加了一个 post_save
信号,该信号调用一个将任务添加到 celery 的函数。 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")
我不会详细介绍设置芹菜的细节,那里有很多信息。
现在我将尝试弄清楚如何在通知实例更新后更新任务,但那是完全不同的故事。
我正在努力解决以下问题。
我正在尝试创建一个自定义信号,该信号将在当前时间等于我模型的 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)
在我通读了所有文档之后,我没有找到关于如何实现这种信号的信息。
有什么想法吗?
更新:
能够丢弃不相关任务的不那么天真的方法:
在 django 的文档中有两个有趣的信号可以帮助您完成此任务:pre_save and post_save。
这取决于您的需要,但假设您想在保存模型后检查模型的 notify_on
是否等于当前日期(实际上是在调用 save()
或 create()
方法之后)。如果是你的情况,你可以这样做:
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 信号会触发。
奖励:要对您的实例执行循环并定期处理操作,您可能需要 async
worker 和 Queue
数据库(主要是, Celery
与 Redis or RabbitMQ
).
好的,感谢@SergeyPugach 的评论,我完成了以下操作:
添加了一个 post_save
信号,该信号调用一个将任务添加到 celery 的函数。 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")
我不会详细介绍设置芹菜的细节,那里有很多信息。
现在我将尝试弄清楚如何在通知实例更新后更新任务,但那是完全不同的故事。