You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Serializer计算的小时范围过滤Django QuerySet?

现有如下MyModelSerializer,通过SerializerMethodField计算hour字段(当前时间与created_at的时间差,以小时为单位):

class MyModelSerializer(serailizers.ModelSerializer):
        hour = serializers.SerializerMethodField()

        def get_hour(self, obj):
           created_at = obj.created_at # datetime
           now = datetime.now()
           return (now - datetime).total_seconds() // 3600
        
        class Meta:
           model = MyModel
           fields = "__all__"

需要实现三个静态过滤功能:

  1. 过滤出hour≤3的列表
  2. 过滤出hour在3-12之间的列表
  3. 过滤出hour>12的列表
    当前过滤方式仅能匹配精确小时值,无法满足需求。期望通过如下参数实现对应过滤:
upto_3h = request.GET.get("upto_3hr", False)
     if upto_3h:
         # filter which has hour less or equal to 3h
     between_3_to_12 = request.GET.get("between_3_to_12", False)
     if between_3_to_12:
         # filter accordingly

     above_12 = request.GET.get("above_12", False)
     if above_12:
         # filter accordingly
          

请问如何实现上述基于小时范围的Django QuerySet过滤?

解决方案

第一步:修正Serializer的时间计算错误

原Serializer的get_hour方法存在两处问题:计算时间差时误用变量、未使用Django时区感知时间,修正后代码如下:

from django.utils import timezone
from rest_framework import serializers
from .models import MyModel

class MyModelSerializer(serializers.ModelSerializer):
    hour = serializers.SerializerMethodField()

    def get_hour(self, obj):
        created_at = obj.created_at
        now = timezone.now()
        # 计算时间差并转为小时(向下取整)
        return (now - created_at).total_seconds() // 3600
    
    class Meta:
        model = MyModel
        fields = "__all__"

第二步:在视图层实现QuerySet范围过滤

核心是直接通过数据库层面的时间比较完成过滤,避免先序列化再过滤的性能损耗,同时保证范围判断准确。注意request.GET获取的参数为字符串,需处理有效值判断:

from django.utils import timezone
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import MyModel
from .serializers import MyModelSerializer
from datetime import timedelta

class MyModelListView(APIView):
    def get(self, request):
        queryset = MyModel.objects.all()
        
        # 过滤hour ≤3的记录(创建时间在3小时内)
        upto_3h = request.GET.get("upto_3hr", "").lower()
        if upto_3h in ('true', '1'):
            three_hours_ago = timezone.now() - timedelta(hours=3)
            queryset = queryset.filter(created_at__gte=three_hours_ago)
        
        # 过滤hour在3-12之间的记录(创建时间在3-12小时前)
        between_3_to_12 = request.GET.get("between_3_to_12", "").lower()
        if between_3_to_12 in ('true', '1'):
            twelve_hours_ago = timezone.now() - timedelta(hours=12)
            three_hours_ago = timezone.now() - timedelta(hours=3)
            queryset = queryset.filter(created_at__gte=twelve_hours_ago, created_at__lt=three_hours_ago)
        
        # 过滤hour >12的记录(创建时间超过12小时)
        above_12 = request.GET.get("above_12", "").lower()
        if above_12 in ('true', '1'):
            twelve_hours_ago = timezone.now() - timedelta(hours=12)
            queryset = queryset.filter(created_at__lt=twelve_hours_ago)
        
        serializer = MyModelSerializer(queryset, many=True)
        return Response(serializer.data)

补充说明

  • 数据库层面过滤能减少数据查询量,比序列化后再过滤效率更高;
  • 若需支持多参数同时生效,可根据业务需求调整逻辑(比如添加参数互斥判断,或合并过滤条件)。

内容的提问来源于stack exchange,提问作者Mark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 08:06:28