gpt4 book ai didi

python - 在 Django Graphene Relay 中启用基于 PK 的过滤,同时保留全局 ID

转载 作者:太空狗 更新时间:2023-10-29 21:59:08 25 4
gpt4 key购买 nike

问题

我在我们的 GraphQL 服务器上使用带有中继的 django-graphene。该实现强加了一个 Global ID requirementgraphene.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 字段,可能会强制它使用不同的字段名称,例如 gid2. 找到一种方法将 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' contains fields that are not defined on this 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"
}
}
}

But I have a fairly strong fear this will break something downstream, at the level of caching perhaps? Also this does not allow filtering by ID still since filtering depends on DjangoFilterConnectionField

请求

我现在卡住了。我有几个问题:

  1. 一开始这是一个不寻常的要求吗?我问错了吗问我何时希望保留按 pk 过滤的能力
  2. 是否有解决此问题的标准模式?

Github上的相关问题

https://github.com/graphql-python/graphene-django/issues/349

版本

  • Graphite 烯-django==2.1.0
  • django==1.9.12
  • django-filter==1.0.1
  • python==2.7.13

最佳答案

我不确定你是否仍然想要答案,但至少让我试着回答你的问题。如果我的理解有误,请更正。我只是愿意帮忙

实际上 pk 应该是 DetailView 而不是与 filter 一起使用的 ListView

requirements.txt

graphene-django==2.7.1
django==3.0.1
django-filter==2.2.0
python==3.8.1

模型.py

from django.contrib.auth import get_user_model
from django.db import models

User = get_user_model()


class Objection(models.Model):
detail = models.TextField(null=True, blank=True)
hidden = models.BooleanField(default=False)
report = models.BooleanField(default=False)
created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='objections',
related_query_name='objection')

nodes.py

import django_filters
import graphene
from graphene import relay
from graphene_django import DjangoObjectType

from multy_herr.objections.models import Objection


class ObjectionFilter(django_filters.FilterSet):
pk = django_filters.NumberFilter(field_name='pk')

class Meta:
model = Objection
fields = [
'pk',
]


class ObjectionNode(DjangoObjectType):
pk = graphene.Field(type=graphene.Int, source='id')

class Meta:
model = Objection
fields = [
'id',
'pk',
'detail',
'hidden',
'report',
]
filter_fields = {
'pk': ['exact'],
'detail': ['icontains', 'istartswith'],
'created_by__name': ['icontains', ],
'hidden': ['exact'],
'report': ['exact'],
}
interfaces = (relay.Node,)


查询.py

import graphene
from graphene import relay
from graphene_django.filter import DjangoFilterConnectionField

from multy_herr.objections.grapheql.nodes import ObjectionNode, ObjectionFilter
from multy_herr.objections.models import Objection


class ObjectionQuery(graphene.ObjectType):
objection = relay.Node.Field(ObjectionNode)
all_objections = DjangoFilterConnectionField(ObjectionNode,
filterset_class=ObjectionFilter)

def resolve_all_objections(self, info, **kwargs):
if info.context.user.is_authenticated is False:
return Objection.objects.none()
return Objection.objects.filter(created_by=info.context.user)

这里我在query中留了注释以供类比。使用我的 hackish 解决方案 Insomnia 应用程序将用 Unknown argument pk ... 警告我。但是有效

查询

query{
# objection(id: "T2JqZWN0aW9uTm9kZTo1"){
# id
# report
# hidden
# }
allObjections(pk: 5){
edges{
node{
id
pk
hidden
report
}
}
}
}

响应

{
"data": {
"allObjections": {
"edges": [
{
"node": {
"id": "T2JqZWN0aW9uTm9kZTo1",
"pk": 5,
"hidden": false,
"report": false
}
}
]
}
}
}

关于python - 在 Django Graphene Relay 中启用基于 PK 的过滤,同时保留全局 ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54328681/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com