【问题标题】:Using dateadd in django filter在 django 过滤器中使用 dateadd
【发布时间】:2016-03-03 01:51:35
【问题描述】:

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

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

我需要能够过滤当前处于活动状态的订阅,例如开始日期

我找不到 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)

【问题讨论】:

    标签: python django postgresql django-orm


    【解决方案1】:

    这里是 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))
    

    【讨论】:

      【解决方案2】:

      我最终编写了一个自定义 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 技巧才能正确解析两个字段名称

      【讨论】:

      • 对于那些希望在 MS SQL Server 中执行此操作的人,可以这样做:function = "DATEADD"template = '%(function)s(DAY, %(expressions)s)' 并使用天数作为第一个参数。
      • 文档字符串提到了end_date__gt=datetime.now,但应该是end_date__gt=datetime.now()
      猜你喜欢
      • 2013-08-18
      • 2012-09-18
      • 1970-01-01
      • 2018-10-04
      • 2017-12-25
      • 2010-10-26
      • 2018-07-13
      • 1970-01-01
      • 2013-01-24
      相关资源
      最近更新 更多