如何在几天内自行更新字段?

时间:2019-08-10 13:16:07

标签: django django-models

我正在一个项目中,我正在接受用户付款。到期日是自付款日起30天。最初,is_due字段为false,但是我希望将其更改为true,而不是在截止日期只有7天时手动更新。即使到处查找,我也没有解决办法。

模型

class Payment(models.Model):
    username = models.ForeignKey(UserProfile,on_delete = models.CASCADE, related_name='name')
    amount = models.IntegerField()
    date = models.DateField(blank=False, default = datetime.datetime.now())
    due_date = models.DateField()
    payment_mode = models.CharField(max_length=50, choices=PaymentModes,null=True,blank=True)
    collected_by = models.ForeignKey(UserProfile,on_delete = None, related_name='collected_by')
    is_due = models.BooleanField(default = False)

    def __str__(self):
        return self.username.user.username

    def save(self, *args, **kwargs):
        self.due_date = self.date + monthdelta(1)
        dt = self.due_date-datetime.date.today()
        if dt.days <=7:
            self.is_due = True
        else:
            self.is_due = False

        super(Payment, self).save(*args, **kwargs)

1 个答案:

答案 0 :(得分:2)

安排任务以更新行通常不是一个好主意,因为这不是一个非常可靠的解决方案。如果计划内存中的任务,则服务器的重新启动将导致不触发计划的任务。您可以使用 celery 之类的工具来使用“持久”计划的任务,但这需要花一些精力来设置它,而且两种解决方案都不“精确”:在任务执行之前可能要花一些额外的时间被触发。

due_date设置为date并保留一个月可能同样适用:您这里有重复数据,这往往很糟糕。如果due_date始终是date,又多了一个月,则您正在浪费磁盘空间。此外,save()函数不会总是触发:例如,如果您批量更新,Django将绕过 save函数,因此您的数据可能不一致。

处理此问题的最简单方法是注释查询集,例如在管理器中:

from django.db.models import BooleanField, ExpressionWrapper, Q
import datetime
from datetime import date, timedelta

class PaymentManager(models.Manager):

    def get_queryset(self):
        return super().get_queryset().annotate(
            is_due=ExpressionWrapper(
                Q(due_date__lt=datetime.date.today()-timedelta(days=7)),
                output_field=BooleanField()
            )
        )

class Payment(models.Model):
    username = models.ForeignKey(UserProfile,on_delete = models.CASCADE, related_name='name')
    amount = models.IntegerField()
    date = models.DateField(blank=False, default=date.today)
    due_date = models.DateField()
    payment_mode = models.CharField(max_length=50, choices=PaymentModes,null=True,blank=True)
    collected_by = models.ForeignKey(UserProfile,on_delete = None, related_name='collected_by')

    objects = PaymentManager()

    def __str__(self):
        return self.username.user.username

    def save(self, *args, **kwargs):
        self.due_date = self.date + monthdelta(1)
        super(Payment, self).save(*args, **kwargs)

请注意,您的date = DateField(..)的默认值应该为date.today,而不是 date.today() ,因为通过调用它,它将将启动服务器的日期(而不是创建日期)设置为默认日期。