如何在Django酒店管理系统中实现预订到期前6小时的定时续住通知功能
如何在Django酒店管理系统中实现预订到期前6小时的定时续住通知功能
嘿,看起来你已经找对了方向——用定时任务处理续住通知需求完全可行,只是在细节上需要调整优化。我来帮你完善这个方案:
一、修正核心逻辑并避免重复发送
你的代码思路没问题,但有两个关键细节需要调整:
- 精准筛选目标订单:当前筛选是找「现在到6小时内到期」的预订,但我们要针对「距离到期不足6小时且未发过通知」的订单。建议给
Reservation模型加一个标记字段,避免重复发送通知。 - 生成邮件可用的绝对URL:
reverse生成的是相对路径,邮件里的链接必须是完整的绝对地址,需要结合站点域名拼接。
先给Reservation模型新增标记字段:
# models.py from django.db import models from django.contrib.auth.models import User class Reservation(models.Model): # 保留你原有的字段 guest = models.ForeignKey(User, on_delete=models.CASCADE) end_date = models.DateTimeField() # 新增字段:标记是否已发送续住通知 renewal_notification_sent = models.BooleanField(default=False)
然后优化你的cron任务代码:
# notification/cron.py from datetime import datetime, timedelta from django.conf import settings from django.core.mail import send_mail from django.urls import reverse from django_cron import CronJobBase, Schedule from .models import Reservation class SendRenewalNotification(CronJobBase): RUN_EVERY_MINS = 60 # 每小时运行一次 schedule = Schedule(run_every_mins=RUN_EVERY_MINS) code = 'notification.send_renewal_notification' def do(self): now = datetime.now() six_hours_later = now + timedelta(hours=6) # 筛选:未发过通知、且到期时间在接下来6小时内的预订 reservations = Reservation.objects.filter( end_date__gt=now, end_date__lte=six_hours_later, renewal_notification_sent=False ) for reservation in reservations: user = reservation.guest reservation_id = reservation.pk # 拼接绝对URL update_url = f"{settings.SITE_URL}{reverse('update_reservation', args=[reservation_id])}" view_reservations_url = f"{settings.SITE_URL}{reverse('view_reservations')}" subject = 'Renew Your Room Reservation' message = f'Dear {user.username}, your room reservation is ending soon (within 6 hours). Would you like to renew it?' message += f'\n\nClick the link below to update your reservation:\n{update_url}' message += f'\n\nYou can also view all your reservations here: {view_reservations_url}' try: send_mail( subject, message, settings.DEFAULT_FROM_EMAIL, [user.email], fail_silently=False ) # 标记为已发送,避免重复通知 reservation.renewal_notification_sent = True reservation.save(update_fields=['renewal_notification_sent']) except Exception as e: # 可选:记录发送失败的日志,方便排查问题 import logging logger = logging.getLogger(__name__) logger.error(f"Failed to send notification to {user.email}: {str(e)}")
二、配置定时任务生效
假设你使用的是django-cron库,按以下步骤配置:
- 在
settings.py的INSTALLED_APPS中添加:INSTALLED_APPS = [ # 其他应用 'django_cron', ] - 在
settings.py中注册你的定时任务:DJANGO_CRON_JOBS = [ ('notification.send_renewal_notification', '*/60 * * * *'), # 每小时运行一次 ] - 运行迁移以应用新增的模型字段:
python manage.py makemigrations python manage.py migrate - 生产环境启动定时任务:
用系统cron定期调用Django的定时任务命令,比如编辑系统crontab:
开发环境可以直接运行crontab -e # 添加一行,替换为你的虚拟环境和项目路径 0 * * * * /path/to/venv/bin/python /path/to/project/manage.py runcrons >> /var/log/django_cron.log 2>&1python manage.py runcrons测试。
三、额外注意事项
- 时区一致性:确保
settings.py中的TIME_ZONE配置正确,避免时区偏差导致通知发送时间错误。 - 邮件测试:开发环境可以用控制台邮件后端查看内容,无需实际发送:
# settings.py EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
备注:内容来源于stack exchange,提问作者samuelkaris
相关产品推荐
相关产品推荐

