我在GraphQL Server上使用django-graphene和Relay。该实现在Global ID requirement类中强加了一个graphene.relay.Node
,它覆盖并隐藏了Django的ID字段。
结果,我可以像这样查询:
{
allBatches(id:"QmF0Y2hOb2RlOjE=") {
edges {
node {
id
pk
}
}
}
}
得到这个回应:
{
"data": {
"allBatches": {
"edges": [
{
"node": {
"id": "QmF0Y2hOb2RlOjE=",
"pk": 1
}
}
]
}
}
}
但是,我失去的是能够按对象本身的原始ID(或PK)字段进行过滤:
{
allBatches(id:1) {
edges {
node {
id
pk
}
}
}
}
实际上,我根本无法通过ID过滤对象。我可以想到两个可能的解决办法:1。防止django-graphene-relay劫持和遮蔽id
字段,也许强迫它使用不同的字段名称,如gid
2.找到一种方法将pk
包括在内可作为属性和过滤器使用的特殊字段
我在1上没有取得任何进展,因为看起来好像django-graphene
(也许是接力标准)强加了这个领域被称为id
的限制。我看到id
已被用作多个地方的魔术字符串,并且似乎没有更改字段名称的标准方法。
在2,我可以让这个属性与这样的Mixin
一起工作:
class PKMixin(object):
pk = graphene.Field(type=graphene.Int, source='pk')
但是,我无法通过django-filter
进行过滤工作,因为FilterSet
没有声明字段pk
并打破以下错误
'Meta.fields'包含未在此FilterSet上定义的字段:pk
我尝试了以下方法:
class PKFilteringNode(Node):
@classmethod
def get_node_from_global_id(cls, info, global_id, only_type=None):
# So long as only_type is set; if we detect that the global_id is a pk and not a global ID;
# then coerce it to be a proper global ID before fetching
if only_type:
try:
int(global_id)
global_id = cls.to_global_id(only_type._meta.name, global_id)
return super(PKFilteringNode, cls).get_node_from_global_id(info, global_id, only_type)
except ValueError:
pass
return super(PKFilteringNode, cls).get_node_from_global_id(info, global_id, only_type)
现在我可以使用GraphQL来执行此操作:
{
batchA: batch(id: "QmF0Y2hOb2RlOjE=") {
id
name
}
batchB: batch(id: 1) {
id
name
}
}
{
"data": {
"batchA": {
"id": "QmF0Y2hOb2RlOjE=",
"name": "Default Batch"
},
"batchB": {
"id": "QmF0Y2hOb2RlOjE=",
"name": "Default Batch"
}
}
}
但我有一种相当强烈的恐惧,这可能会破坏下游的某些东西,或许在缓存水平?此外,由于过滤依赖于
DjangoFilterConnectionField
,因此不允许按ID过滤
我现在卡住了。我有几个问题:
https://github.com/graphql-python/graphene-django/issues/349
您是否尝试过解决方案2,但使用id作为源代码?
class PKMixin(object):
pk = graphene.Field(type=graphene.Int, source='id')
此外,如果您只想获取单个记录,则无论如何都不应通过连接字段。您应该在架构上定义类似batchByPk
字段的内容。
最后需要注意的是,目前graphene-django的DjangoFilterConnectionField
并没有以有效的方式实现,所以你甚至可能都不想使用它。