我正在尝试使用Django和Graphene执行GraphQL查询。要使用ID查询单个对象,我做了以下操作:
{
samples(id:"U2FtcGxlU2V0VHlwZToxMjYw") {
edges {
nodes {
name
}
}
}
}
它运行正常。当我尝试使用多个ID进行查询时出现问题,如下所示:
{
samples(id_In:"U2FtcGxlU2V0VHlwZToxMjYw, U2FtcGxlU2V0VHlwZToxMjYx") {
edges {
nodes {
name
}
}
}
}
在后一种情况下,出现以下错误:
argument should be a bytes-like object or ASCII string, not 'list'
这是在django-graphene
class SampleType(DjangoObjectType):
class Meta:
model = Sample
filter_fields = {
'id': ['exact', 'in'],
}
interfaces = (graphene.relay.Node,)
class Query(object):
samples = DjangoFilterConnectionField(SampleType)
def resolve_sample_sets(self, info, **kwargs):
return Sample.objects.all()
答案 0 :(得分:4)
GlobalIDMultipleChoiceFilter
可以解决此问题。您可以创建类似
from django_filters import FilterSet
from graphene_django.filter import GlobalIDMultipleChoiceFilter
class BookFilter(FilterSet):
author = GlobalIDMultipleChoiceFilter()
并通过
使用它{
books(author: ["<GlobalID1>", "<GlobalID2>"]) {
edges {
nodes {
name
}
}
}
}
仍然不够完美,但是对自定义代码的需求已降至最低。
答案 1 :(得分:1)
您可以轻松地使用过滤器,只需将其放入节点即可。
TIME_ZONE = 'America/New_York'
然后在查询中只使用-
class ReportFileFilter(FilterSet):
id = GlobalIDMultipleChoiceFilter()
这是对graphql django的中继实现。
答案 2 :(得分:1)
在介绍这些答案时,似乎没有一个对我有用,但是通过一些小的更改,我设法解决了以下问题:
您可以为您的对象类型创建自定义FilterSet
类,并使用GlobalIDMultipleChoiceFilter
过滤字段。例如:
from django_filters import FilterSet
from graphene_django.filter import GlobalIDFilter, GlobalIDMultipleChoiceFilter
class SampleFilter(FilterSet):
id = GlobalIDFilter()
id__in = GlobalIDMultipleChoiceFilter(field_name="id")
class Meta:
model = Sample
fields = (
"id_in",
"id",
)
我碰到的一件事情是,您无法使用此方法定义filter_fields 。相反,您只需要专门依赖自定义FilterSet
类,就可以使对象类型有效地如下所示:
from graphene import relay
from graphene_django import DjangoObjectType
class SampleType(DjangoObjectType):
class Meta:
model = Sample
filterset_class = SampleFilter
interfaces = (relay.Node,)
答案 3 :(得分:0)
我也难以实现'in'过滤器-它现在似乎在graphene-django中实现不当,并且无法按预期工作。以下是使其工作的步骤:
from base64 import b64decode
def get_pk_from_node_id(node_id: str):
"""Gets pk from node_id"""
model_with_pk = b64decode(node_id).decode('utf-8')
model_name, pk = model_with_pk.split(":")
return pk
class SampleType(DjangoObjectType):
class Meta:
model = Sample
filter_fields = {
'id': ['exact'],
}
interfaces = (graphene.relay.Node,)
class Query(object):
samples = DjangoFilterConnectionField(SampleType, id__in=graphene.List(graphene.ID))
def resolve_samples(self, info, **kwargs):
# filter_field for 'in' seems to not work, this hack works
id__in = kwargs.get('id__in')
if id__in:
node_ids = kwargs.pop('id__in')
pk_list = [get_pk_from_node_id(node_id) for node_id in node_ids]
return Sample._default_manager.filter(id__in=pk_list)
return Sample._default_manager.all()
这将允许您使用以下api调用过滤器。请注意在签名中使用实际数组(我认为这比发送逗号分隔的值字符串更好)。该解决方案仍然允许您向请求中添加其他过滤器,它们将正确链接在一起。
{
samples(id_In: ["U2FtcGxlU2V0VHlwZToxMjYw", "U2FtcGxlU2V0VHlwZToxMjYx"]) {
edges {
nodes {
name
}
}
}
}
答案 4 :(得分:0)
另一种方法是告诉graphene_django的Relay过滤器也处理一个列表。此过滤器已在graphene_django的mixin中注册,并应用于您定义的任何过滤器。
这是我的解决方案:
from graphene_django.filter.filterset import (
GlobalIDFilter,
GrapheneFilterSetMixin,
)
from graphql_relay import from_global_id
class CustomGlobalIDFilter(GlobalIDFilter):
"""Allow __in lookup for IDs"""
def filter(self, qs, value):
if isinstance(value, list):
value_lst = [from_global_id(v)[1] for v in value]
return super(GlobalIDFilter, self).filter(qs, value_lst)
else:
return super().filter(qs, value)
# Fix the mixin defaults
GrapheneFilterSetMixin.FILTER_DEFAULTS.update({
AutoField: {"filter_class": CustomGlobalIDFilter},
OneToOneField: {"filter_class": CustomGlobalIDFilter},
ForeignKey: {"filter_class": CustomGlobalIDFilter},
})