问题描述
想法是创建芹菜任务,其中创建后1个月( created_at 字段) 使用5%的折扣更新价格字段。
型号:
class Product(models.Model):
price = models.DecimalField(max_digits=15,decimal_places=2,help_text="Current price of products")
old_price = models.DecimalField(max_digits=15,help_text="Old price of products",null=True,blank=True)
created_at = models.DateTimeField(auto_Now_add=True,editable=False)
解决方法
您可以编写一些逻辑来检查当前日期是否已过created_at
,而不是执行芹菜任务,并在这种情况下应用折扣。例如,使用https://jwt.io/:
from dateutil.relativedelta import relativedelta
from django.utils.timezone import now
from decimal import Decimal
class Product(models.Model):
price = models.DecimalField(
max_digits=15,decimal_places=2,help_text='Current price of products'
)
created_at = models.DateTimeField(auto_now_add=True,editable=False)
@property
def real_price(self):
if created_at + relativedelta(month=1) < now():
return self.price * Decimal('0.95')
return self.price
或者我们可以使用注释:
from django.utils.timezone import now
from django.db.models import Case,DecimalField,F,Value,When
from dateutil.relativedelta import relativedelta
from decimal import Decimal
Product.objects.annotate(
real_price=Case(
When(
created_at__lt=now() - relativedelta(month=1),then=F('price') * Decimal('0.95')
),default=F('price'),output_field=DecimalField(max_digits=15,decimal_places=2)
)
)
这里,来自查询集的Product
具有额外的属性.real_price
,因此一个月后可以打折。
@Willem建议使用一种很好的方法,但是如果您仍然想更新字段本身,则可以使用每天运行的芹菜任务。这样,您不必为每个产品实例运行celery任务,而是每天运行一次并检查所有产品并将折扣应用到30天前创建的产品的定期celery任务:
from datetime import timedelta
from django.utils import timezone
@task
def apply_discount():
Product.objects.filter(
created__lte=timezone.now() - timedelta(days=30),created__gt=timezone.now() - timedelta(days=31)
).update(price=F('price') * Decimal('0.95'))
然后将任务注册到您的设置文件中:
CELERY_BEAT_SCHEDULE = {
'apply-discount': {
'task': 'app.tasks.apply_discount','schedule': crontab(hour=1,minute=0),}
}
这会在每天凌晨1点运行任务