如何使用 `django-filters` 编写将在整数字段上使用范围过滤器的 GraphQL 查询?
How to write a GraphQL query that will use a range filter on an integer field using `django-filters`?
我在我的 GraphQL API 中使用 graphene-python
、django-filters
和 relay
。假设我有一个类型 FrameType
,它有一个整数字段 time_offset
,我希望能够在其上使用 range - 只询问帧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
?
遗憾的是,这是不可能的。但是,有一个解决方法
将您的过滤器class调整为
<b>def custom_range_filter_method(queryset, field_name, value):
if value:
queryset = queryset.filter(**{f'{field_name}__range': value.split(',')})
return queryset</b>
class FrameFilter(django_filters.FilterSet):
time_offset = <b>filters.Filter(method=custom_range_filter_method)</b>
class Meta:
model = models.Frame
fields = ("time_offset",)
现在用
查询架构
query Frame {
frames(first: 20, <b>timeOffset: "4350,5000"</b>) {
edges {
node {
timeOffset
}
}
}
参考
- 使用
Filter.method
--(django-filter
doc) 自定义过滤结果
您可以在 Django 的查询集级别处理 range 选项,而不会干扰现有的中继查询。
在你的情况下,
- 将
start_time_offset
和 end_time_offset
参数传递给 DjangoConnectionField
- 覆盖
resolve_frames
- 如果
start_time_offset
或 end_time_offset
由用户提供 return objects.all()
,则在 django 查询集上进行过滤
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
}
}
}
它有点旧,但由于它可能对其他人有帮助,您可以查看此 thread, it used django filterset for DateRangeFiled and I think you can use a similar approach for integers using filterset RangeFilter. Also check this 以获取有关石墨烯中过滤器集的更多信息。
您需要做的就是更新您的 FrameType class,如下所示:
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
}
}
}
我在我的 GraphQL API 中使用 graphene-python
、django-filters
和 relay
。假设我有一个类型 FrameType
,它有一个整数字段 time_offset
,我希望能够在其上使用 range - 只询问帧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
?
遗憾的是,这是不可能的。但是,有一个解决方法
将您的过滤器class调整为
<b>def custom_range_filter_method(queryset, field_name, value):
if value:
queryset = queryset.filter(**{f'{field_name}__range': value.split(',')})
return queryset</b>
class FrameFilter(django_filters.FilterSet):
time_offset = <b>filters.Filter(method=custom_range_filter_method)</b>
class Meta:
model = models.Frame
fields = ("time_offset",)
现在用
查询架构query Frame {
frames(first: 20, <b>timeOffset: "4350,5000"</b>) {
edges {
node {
timeOffset
}
}
}
参考
- 使用
Filter.method
--(django-filter
doc) 自定义过滤结果
您可以在 Django 的查询集级别处理 range 选项,而不会干扰现有的中继查询。
在你的情况下,
- 将
start_time_offset
和end_time_offset
参数传递给DjangoConnectionField
- 覆盖
resolve_frames
- 如果
start_time_offset
或end_time_offset
由用户提供 returnobjects.all()
,则在 django 查询集上进行过滤
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
}
}
}
它有点旧,但由于它可能对其他人有帮助,您可以查看此 thread, it used django filterset for DateRangeFiled and I think you can use a similar approach for integers using filterset RangeFilter. Also check this 以获取有关石墨烯中过滤器集的更多信息。
您需要做的就是更新您的 FrameType class,如下所示:
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
}
}
}