如何使用`django-filters`编写将在整数字段上使用范围过滤器的GraphQL查询?
Posted
技术标签:
【中文标题】如何使用`django-filters`编写将在整数字段上使用范围过滤器的GraphQL查询?【英文标题】:How to write a GraphQL query that will use a range filter on an integer field using `django-filters`? 【发布时间】:2021-01-17 08:38:22 【问题描述】:我在我的 GraphQL API 中使用 graphene-python
、django-filters
和 relay
。假设我有一个类型FrameType
,它有一个整数字段time_offset
,我希望能够在它上面使用一个范围 - 只询问其中有time_offset
的帧给定范围。我根据graphene-python docs 用自定义FilterSet
准备了我的schema.py
:
import django_filters
from graphene import ObjectType, relay
from graphene_django import DjangoObjectType, filter
from my_app.blabla import models
class FrameFilter(django_filters.FilterSet):
time_offset = django_filters.RangeFilter()
class Meta:
model = models.Frame
fields = ("time_offset",)
class FrameType(DjangoObjectType):
class Meta:
model = models.Frame
filterset_class = FrameFilter
interfaces = (relay.Node,)
class Query(ObjectType):
frames = filter.DjangoFilterConnectionField(FrameType)
class Meta:
abstract = True
但是,我现在不知道如何查询timeOffset
字段。我在网上找不到django_filters.RangeFilter
字段的示例。这是我尝试过的查询:
query Frame
frames(first: 20, timeOffset: "\"gt\":\"4350\", \"lt\":\"5000\"")
edges
node
timeOffset
...还有这些替代品:
timeOffset: "\"gt\":4350, \"lt\":5000"
timeOffset: "\"start\":\"4350\", \"end\":\"5000\""
timeOffset: "\"min\":\"4350\", \"max\": \"4500\""
timeOffset: "[\"4350\", \"5000\"]"
timeOffset: "[4350, 5000]"
timeOffset: "[4350]"
timeOffset: "4350,5000"
这些查询不会引发任何错误,但它们也不会过滤(返回所有结果)。我迷路了,我不确定我是否还没有找到正确的语法,或者我的后端代码中可能有一些错误。我应该如何使用和查询字段上的django_filters.RangeFilter
?
【问题讨论】:
【参考方案1】:很遗憾,这是不可能的。但是,有一个解决方法
将您的过滤器类调整为
def custom_range_filter_method(queryset, field_name, value):
if value:
queryset = queryset.filter(**f'field_name__range': value.split(','))
return queryset
class FrameFilter(django_filters.FilterSet):
time_offset = filters.Filter(method=custom_range_filter_method)
class Meta:
model = models.Frame
fields = ("time_offset",)
现在使用
查询架构query Frame
frames(first: 20, timeOffset: "4350,5000")
edges
node
timeOffset
参考
使用Filter.method
--(django-filter
doc)自定义过滤结果
【讨论】:
【参考方案2】:您可以在 Django 的查询集级别处理 range 选项,而不会干扰现有的中继查询。
在你的情况下,
-
将
start_time_offset
和end_time_offset
参数传递给DjangoConnectionField
覆盖resolve_frames
如果start_time_offset
或end_time_offset
由用户提供,则过滤django查询集,否则返回objects.all()
class Query(ObjectType):
frames = filter.DjangoFilterConnectionField(FrameType, start_time_offset=graphene.Int(), end_time_offset=graphene.Int())
def resolve_frames(self, info, start_time_offset=None, end_time_offset=None, **kwargs):
if start_time_offset and end_time_offset:
return Frame.objects.filter(time_offset__range=(start_time_offset, end_time_offset))
elif start_time_offset:
return Frame.objects.filter(time_offset__gte=start_time_offset)
elif end_time_offset:
return Frame.objects.filter(time_offset__lte=end_time_offset)
return Frame.objects.all()
现在您可以使用中继提供的常规过滤器对其进行查询:
query Frame
frames(last: 5, startTimeOffset: 4350, endTimeOffset:5000)
edges
node
timeOffset
【讨论】:
【参考方案3】:它有点旧,但因为它可能对其他人有帮助,你可以检查这个thread,它使用 django 过滤器集作为 DateRangeFiled,我认为你可以使用过滤器集 RangeFilter 对整数使用类似的方法。另请查看this,了解有关石墨烯中过滤器集的更多信息。
【讨论】:
【参考方案4】:您需要做的就是更新您的 FrameType 类,如下所示:
class FrameType(DjangoObjectType):
class Meta:
model = models.Frame
filterset_fields =
'time_offset': ['range']
interfaces = (relay.Node,)
您不需要为此设置自定义过滤器。 然后可以查询如下:
query Frame
frames(first: 20, timeOffset_Range: ["4350", "5000"])
edges
node
timeOffset
【讨论】:
以上是关于如何使用`django-filters`编写将在整数字段上使用范围过滤器的GraphQL查询?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 django-filters 过滤 ModelViewSet 中的自定义 url
Django-Filter 包:如何过滤对象以创建统计信息而不是列表
如何在django-select2中使用django-filter?