我在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上没有取得任何进展,因为似乎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"
}
}
}
但是我非常担心这会破坏下游的东西, 在缓存级别上? 同样,这仍然不允许通过ID进行过滤,因为过滤取决于
DjangoFilterConnectionField
我现在被困住了。我有几个问题:
https://github.com/graphql-python/graphene-django/issues/349
答案 0 :(得分:0)
您是否尝试过解决方案2,但是使用id作为源?
class PKMixin(object):
pk = graphene.Field(type=graphene.Int, source='id')
此外,如果您只想获取一条记录,则无论如何都不应通过连接字段。您应该在架构上定义类似batchByPk
字段的内容。
要了解的最后一件事是,当前没有以有效的方式实现graphene-django的DjangoFilterConnectionField
,因此您甚至都不想使用它。
答案 1 :(得分:0)
我不确定您是否仍然想要答案,但至少让我尝试回答您的问题。如果我的理解错误,请更正。我只是愿意帮助
实际上pk
应该是DetailView
,而不是ListView
与filter
一起使用。
requirements.txt
graphene-django==2.7.1
django==3.0.1
django-filter==2.2.0
python==3.8.1
models.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,)
queries.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
中留下类推。使用我的恶意解决方案Insomnia
,应用程序将通过Unknown arguemnt pk ...
向我发出警告。但是有效
query
query{
# objection(id: "T2JqZWN0aW9uTm9kZTo1"){
# id
# report
# hidden
# }
allObjections(pk: 5){
edges{
node{
id
pk
hidden
report
}
}
}
}
response
{
"data": {
"allObjections": {
"edges": [
{
"node": {
"id": "T2JqZWN0aW9uTm9kZTo1",
"pk": 5,
"hidden": false,
"report": false
}
}
]
}
}
}