在 Django 过滤器中使用 dateadd

Var*_*ant 4 python django postgresql django-orm

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

class SubscriptionProduct(models.Model):    
    start_date = models.DateField()
    duration = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)

我需要能够过滤当前处于活动状态的订阅,例如start_date < now < start_date+duration

我找不到 django 的方式来做到这一点。我可以使用使用 postgres 的 DATEADD 等效的 INTERVAL 的原始 SQL 语句,但我更喜欢使用内置的和非数据库特定的东西。

我假设理想情况下我正在寻找 dateadd 注释方法。就像是:

SubscriptionProduct.objects.annotate(end_date=DateAdd('start_date','duration').filter(start_date__lt=datetime.now, end_date__gte=datetime.now)
Run Code Online (Sandbox Code Playgroud)

Var*_*ant 6

我最终编写了一个自定义的 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()
Run Code Online (Sandbox Code Playgroud)

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