【问题标题】:In Django, how do I construct my queryset to filter by time over slices of time?在 Django 中,如何构建我的查询集以按时间过滤时间片?
【发布时间】:2021-12-27 20:47:46
【问题描述】:

我正在使用 Python 3.9 和 Django 3.2。我有这个价格模型

class Price(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    price = models.FloatField(null=False)
    created = models.DateTimeField(null=False, default=datetime.now)

如果我想获得过去 24 小时内每小时的价格,我可以运行这样的方法

def _get_prices_per_time_slice(self, last_hours=24):
    now = timezone.now()
    end_time = now.replace(second = 0, microsecond = 0)
    start_time = end_time - timedelta(hours=last_hours)
    qset = Price.objects.filter(
        created__range=[start_time, end_time],
        created__minute=end_time.minute
    ).values('price')
    return [r['price'] for r in qset]

但假设我想每隔 X 小时获取一次价格。

def _get_prices_per_time_slice(self, last_hours=24, time_slice_in_hours=4):

因此,如果当前时间是午夜(零秒和分钟),我想获取午夜、晚上 8 点、下午 4 点、中午、上午 8 点和凌晨 4 点的价格。如何添加过滤器以筛选每 X 小时的价格?

【问题讨论】:

  • filter(created__in=list_of_desired_times) 呢?
  • 为什么created__minute=end_time.minute 在里面?
  • 您是否正在寻找午夜、晚上 8 点、下午 4 点等每个时间的单一价格?或所有存储在给定窗口中的价格:` [[晚上 8 点到午夜之间的所有价格],[下午 4 点到晚上 8 点之间的所有价格] , ...]

标签: python-3.x django datetime django-queryset django-filter


【解决方案1】:

您可以通过在 python 中处理时间片过滤来实现这一点。

我的意思是,如果你使用你所拥有的功能。即

def _get_prices_per_time_slice(self, last_hours=24):
    now = timezone.now()
    end_time = now.replace(second = 0, microsecond = 0)
    start_time = end_time - timedelta(hours=last_hours)
    qset = Price.objects.filter(
        created__range=[start_time, end_time],
        created__minute=end_time.minute
    ).values('price')
    return [r['price'] for r in qset]

并将其重写如下,以返回创建的数据并处理返回列表理解中的过滤。

def _get_prices_per_time_slice(self, last_hours=24, time_slice_in_hours=4):
    now = timezone.now()
    end_time = now.replace(second = 0, microsecond = 0)
    start_time = end_time - timedelta(hours=last_hours)
    qset = Price.objects.filter(
        created__range=[start_time, end_time],
        created__minute=end_time.minute
    ).values('price', 'created')
    return [r.get('price') for r in qset if r.get('created').hour % time_slice_in_hours == 0]

【讨论】:

    【解决方案2】:

    python中的range函数有助于指定增量步长值

    语法:range(start, stop, step)

    
    x = range(3, 20, 4)
    
    for n in x:
      print(n)
    #Gives output 
    >>> 3
    >>> 7
    >>> 11
    >>> 15
    >>> 19
    
    

    只需重写created_range以添加步长值time_slice_in_hours

       created__range=[start_time, end_time, time_slice_in_hours] 
    

    选项 1

    
    def _get_prices_per_time_slice(self, last_hours= 24,time_slice_in_hours=4):
        now = timezone.now()
        end_time = now.replace(second = 0, microsecond = 0)
        start_time = end_time - timedelta(hours=last_hours)
        qset = Price.objects.filter(
            created__range=[start_time, end_time, time_slice_in_hours],
            created__minute=end_time.minute
        ).values('price')
        return [r['price'] for r in qset]
    
    

    但是django query set api official documentation 中的语法未能在__range() 函数中提及步骤参数,即created__range 可能不支持它。

    选项 2

    在这种情况下,您可以使用以下函数,您可以使用 Python 的 DateTimeRange 函数 (official documentation) 计算时间范围 x_time_slice_list 并计算为 created__in

    
    from datetimerange import DateTimeRange
    from dateutil.relativedelta import relativedelta
    
    def _get_prices_per_time_slice(self, last_hours= 24,time_slice_in_hours=4):
        now = timezone.now()
        end_time = now.replace(second = 0, microsecond = 0)
        start_time = end_time - timedelta(hours=last_hours)
        x_time_slice_list= []
    
        time_range = DateTimeRange(start_time, end_time)
        for value in time_range.range(relativedelta(hours=+time_slice_in_hours)):
               x_time_slice_list.append(value)
    
        qset = Price.objects.filter(
            created__in= x_time_slice_list,
            created__minute=end_time.minute
        ).values('price')
        return [r['price'] for r in qset]
    
    

    【讨论】:

    • 选项 1 给出错误,但选项 2 似乎有效。
    猜你喜欢
    • 2020-09-08
    • 1970-01-01
    • 2012-04-14
    • 2013-10-27
    • 2019-09-18
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 2022-07-19
    相关资源
    最近更新 更多