You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django酒店管理系统中实现预订到期前6小时的定时续住通知功能

如何在Django酒店管理系统中实现预订到期前6小时的定时续住通知功能

嘿,看起来你已经找对了方向——用定时任务处理续住通知需求完全可行,只是在细节上需要调整优化。我来帮你完善这个方案:

一、修正核心逻辑并避免重复发送

你的代码思路没问题,但有两个关键细节需要调整:

  1. 精准筛选目标订单:当前筛选是找「现在到6小时内到期」的预订,但我们要针对「距离到期不足6小时且未发过通知」的订单。建议给Reservation模型加一个标记字段,避免重复发送通知。
  2. 生成邮件可用的绝对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库,按以下步骤配置:

  1. 在settings.py的INSTALLED_APPS中添加:
    INSTALLED_APPS = [
        # 其他应用
        'django_cron',
    ]
    
  2. 在settings.py中注册你的定时任务:
    DJANGO_CRON_JOBS = [
        ('notification.send_renewal_notification', '*/60 * * * *'),  # 每小时运行一次
    ]
    
  3. 运行迁移以应用新增的模型字段:
    python manage.py makemigrations
    python manage.py migrate
    
  4. 生产环境启动定时任务:
    用系统cron定期调用Django的定时任务命令,比如编辑系统crontab:
    crontab -e
    # 添加一行,替换为你的虚拟环境和项目路径
    0 * * * * /path/to/venv/bin/python /path/to/project/manage.py runcrons >> /var/log/django_cron.log 2>&1
    
    开发环境可以直接运行python manage.py runcrons测试。

三、额外注意事项

  • 时区一致性:确保settings.py中的TIME_ZONE配置正确,避免时区偏差导致通知发送时间错误。
  • 邮件测试:开发环境可以用控制台邮件后端查看内容,无需实际发送:
    # settings.py
    EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
    

备注:内容来源于stack exchange,提问作者samuelkaris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 12:44:44