【问题标题】:Customize django filter model field自定义 django 过滤器模型字段
【发布时间】:2017-03-05 21:43:18
【问题描述】:

我有以下型号

class some_model(models.Model):
    some_date = models.DateTimeField()
    hours = models.IntegerField()

获取当前日期

temp_date = datetime.datetime.now()

现在我想过滤 django 字段,像这样

filter_date = some_date + add timedelta(hours)

然后在 django 过滤器中使用 filter_date

some_model.objects.filter(filter_date__gte = temp_date)

以上可以在 django 中查询?

【问题讨论】:

    标签: python django filter


    【解决方案1】:

    一种更优雅的方式是创建数据库函数。

    假设我们有下面描述的模型。我们的目标是过滤所有在此之前结束的对象。

    from django.db import models
    
    class SomeModel(models.Model):
        date_start = models.DateTimeField()
        duration = models.FloatField()
    

    DataBase函数实现:

    from django.db.models.expressions import Func
    from django.db.models import DateTimeField
    
    
    class Interval(Func):
        function = 'INTERVAL'
        template = "(%(expressions)s * %(function)s '1 %(phylum)s')"
    
        def __init__(self, expression, phylum, **extra):
            output_field = extra.pop('output_field', DateTimeField())
            super(Interval, self).__init__(expression, output_field=output_field, phylum=phylum, **extra)
    

    并使用它。作为 Interval 函数的第一个参数,您可以作为 F('field_name') 或 Value() 或一些 Python 对象传递。作为第二个参数,它可以是:'second'、'minute'、'hour'、'day'。

    objs = (SomeModel.objects.annotate(date_end=F('date_start') + Interval(F('duration'), 'hour')).
    filter(date_end__lte=datetime.datetime.now(pytz.utc)))
    
    • 测试:Django==1.8.15,Postgres:9.4.5

    • 此实现仅适用于 Postgres,对于另一个数据库,您应覆盖相关方法:'as_postgresql'、'as_oracle'

    【讨论】:

      【解决方案2】:

      您可以使用custom QuerySet 做到这一点。我建议创建自定义过滤器方法,而不是覆盖现有的。

      更新基于https://stackoverflow.com/a/33916628/3627387 你可以使用extra实现它

      class CustomQuerySet(models.QuerySet):
          def date_filter(self):
              # using
              return self.extra(where=["some_date + hours * INTERVAL '1 hour' >= %s"], params=[datetime.now()])
      
      class some_model(models.Model):
          some_date = models.DateTimeField()
          hours = models.IntegerField()
      
          objects = CustomQuerySet.as_manager()
      
      # And then in your code
      some_model.objects.date_filter()
      

      【讨论】:

      • 我想在模型字段 (some_date+timedelta(hours)) 中添加 timedelta,然后在 some_date (some_date+timedelta(hours) gte temp_date) 上使用 gte 过滤器。
      • 有什么区别?从数学上讲some_date+timedelta(hours)_gte=temp_datesome_date_gte=temp_date-timedelta(hours) 相同。但是第一个在 django ORM 中是不可能的。所以这就是我和@table 建议你这样做的原因。
      • 小时是我的模型字段,所以我怎样才能通过这个小时到日期过滤器
      • @NIKHILRANE 阅读更新的答案。这在 django 中目前是不可能的。但是您可以为此使用 extra 并使用原始 SQL
      【解决方案3】:

      由于filter_date 不是模型的字段,您建议的查询将出错。

      从我的角度来看,您要做的是获取 some_date 大于 hours 之前的对象。这是实现这一目标的查询:

      some_model.objects.filter(
          some_date__gte=datetime.datetime.now()-datetime.timedelta(hours=hours))
      

      【讨论】:

      • 是的,我知道,但我想自定义该模型文件。
      • filter 方法几乎形成了一个 SQL 查询以在数据库上执行。所以答案是不能对数据库表中不存在的字段使用查找。
      猜你喜欢
      • 2017-11-13
      • 1970-01-01
      • 1970-01-01
      • 2017-11-17
      • 1970-01-01
      • 1970-01-01
      • 2011-09-03
      • 2016-07-01
      • 2012-12-11
      相关资源
      最近更新 更多