在django过滤器中使用dateadd

时间:2015-11-29 09:54:22

标签: python django postgresql django-orm

我有一个模型,按开始日期和持续时间(以天为单位)定义订阅期:

class SubscriptionProduct(models.Model):    
    start_date = models.DateField()
    duration = models.IntegerField()

我需要能够过滤当前有效的订阅,例如 start_date<现在<起始日期+时间

我找不到django这样做的方法。我可以使用使用postgres的DATEADD等效于INTERVAL的原始SQL语句,但我更喜欢使用内置和非db特定的东西。

我认为理想情况下我正在寻找一个dateadd注释方法。类似的东西:

SubscriptionProduct.objects.annotate(end_date=DateAdd('start_date','duration').filter(start_date__lt=datetime.now, end_date__gte=datetime.now)

2 个答案:

答案 0 :(得分:1)

我最终编写了一个自定义的Func表达式,它表达了我正在寻找的东西。 这是特定于Postgresql并且有点hacky但是它可以工作,即使在比上面说明的更复杂的查询中使用时也是如此。

class DateAdd(Func):
    """
    Custom Func expression to add date and int fields as day addition
    Usage: SubscriptionProduct.objects.annotate(end_date=DateAdd('start_date','duration')).filter(end_date__gt=datetime.now)
    """
    arg_joiner = " + CAST("
    template = "%(expressions)s || ' days' as INTERVAL)"
    output_field = DateTimeField()

请注意,我必须执行arg_joiner技巧,以便在子选择表达式中使用时正确解析两个字段名称

答案 1 :(得分:0)

这是 MySQL 的版本:

from django.db.models import Func, DateTimeField

class DateAdd(Func):
    function = 'DATE_ADD'
    template = "%(function)s(%(expressions)s, INTERVAL %(days)i DAY)"
    output_field = DateTimeField()

然后

queryset.annotate(days_added=DateAdd(f'date_field_name', days=1))