【发布时间】:2019-06-17 03:04:41
【问题描述】:
问题
我在我们的 GraphQL 服务器上使用 django-graphene 和 Relay。该实现在graphene.relay.Node 类中强加了一个Global ID requirement,该类覆盖并隐藏了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
我在 1 上没有取得任何进展,因为它看起来好像 django-graphene(也许是中继标准)施加了一个限制,即该字段被称为 id。我看到id 已在多个地方用作魔术字符串,并且似乎没有更改字段名称的标准方法。
解决方案 2
在 2 上,我可以让该属性与 Mixin 一起使用,如下所示:
class PKMixin(object):
pk = graphene.Field(type=graphene.Int, source='pk')
但是,我无法通过django-filter 进行过滤,因为FilterSet 没有声明pk 字段并因以下错误而中断
'Meta.fields' 包含未在此 FilterSet 上定义的字段: PK
2 日更新
我尝试了以下方法:
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"
}
}
}
但是我非常担心这会破坏下游的某些东西, 也许在缓存级别? 此外,这仍然不允许按 ID 过滤,因为过滤取决于
DjangoFilterConnectionField
请求
我现在被困住了。我有几个问题:
- 这是一个不寻常的要求吗?我问错了吗 当我希望保留 按 pk 过滤的能力 时的问题
- 是否有解决此问题的标准模式?
Github 上的相关问题
https://github.com/graphql-python/graphene-django/issues/349
版本
- 石墨烯-django==2.1.0
- django==1.9.12
- django-filter==1.0.1
- python==2.7.13
【问题讨论】:
-
API 始终返回具有派生全局 ID 的节点。作为客户端,如果我需要查找节点,我可以使用相同的标识符。暴露底层 PK 似乎没有必要,除非 A)您正在与之交互的其他一些服务使用 PK 作为参考或 B)从业务规则的角度来看,PK 对客户端很重要(即客户端将 PK 值与执行一些业务逻辑)。为什么觉得有必要公开PK?
-
与 PK 紧密耦合的遗留代码
-
基本上,A) 和 B) 对我们来说都是正确的。
-
带有 ID 的网站 URL 是合法的用例。
-
我考虑过使用石墨烯,但这是一个很大的限制,我可能需要放弃这个想法
标签: python django graphql relay graphene-python