Django 模型对象和石墨烯 get_node
Posted
技术标签:
【中文标题】Django 模型对象和石墨烯 get_node【英文标题】:Django model objects and Graphene get_node 【发布时间】:2018-06-28 22:27:52 【问题描述】:到目前为止,我可以在不需要DjangoObjectType
的情况下使用 Graphene。我尽量避免它,因为我不打算离我的 Django 模型类太近。但是我在使用 Graphene 实现 Relay 时遇到了问题:
class HouseholdNode(graphene.ObjectType):
class Meta:
interfaces = (graphene.relay.Node,)
name = graphene.String()
@classmethod
def get_node(cls, info, id):
return Household.objects.get(pk=id)
这会失败并出现以下错误:
抽象类型节点必须在运行时为字段 Query.node 解析为对象类型,值为“Test”,收到“None”。
“测试”直接来自Household
的__str__
函数。
下一次尝试:
@classmethod
def get_node(cls, info, id):
return cls(Household.objects.get(pk=id))
cls
是 HouseholdNode
。然而,这会产生错误的结果:
"node":
"id": "SG91c2Vob2xkOlRlc3Q=",
"name": null
ID 实际上是“Test”。
有效的解决方案:
@classmethod
def get_node(cls, info, id):
household = Household.objects.get(pk=id)
return cls(name=household.name)
但是,我非常怀疑 Graphene 能为我做的只是这些。我真的必须将真实数据对象包装到HouseholdNode
中吗?我已经有了resolve函数,不能直接用吗?
这些方面的文档非常缺乏,请赐教。
【问题讨论】:
This issue 在 Github 上是相关的。 【参考方案1】:抽象类型(如graphene.relay.node.Node
)由executor 使用graphql.execution.executor.complete_abstract_value
解析。
实际上,以Node
作为接口的ObjectTypes 从石墨烯传递到graphql 层,每个都包装为GrapheneInterfaceType
。每个对象的resolve_type
(最终提供错误的来源)调用graphql.execution.executor.get_default_resolve_type_fn
。
此函数缩小可能返回的类型 (possible_types
),然后遍历这些类型,检查 is_type_of
属性是否可调用以及它是否返回 True。重要的是要注意possible_types
是Node
的用户定义子类,继承自具有is_type_of = None
的graphene.types.objecttype.ObjectType
。因此,您会得到GraphQLError
,因为没有解析任何类型。
解决方案是在你的对象类型上定义一个is_type_of
方法(或者创建一个抽象的ObjectType,你可以使用它已经实现的子类)。例如,graphene-sqlalchemy
中的here is the code 实现了is_type_of
逻辑,而graphene-django
则实现了code is here。
@classmethod
def is_type_of(cls, root, info):
if isinstance(root, SimpleLazyObject):
root._setup()
root = root._wrapped
if isinstance(root, cls):
return True
if not is_valid_django_model(type(root)):
raise Exception((
'Received incompatible instance "".'
).format(root))
model = root._meta.model._meta.concrete_model
return model == cls._meta.model
【讨论】:
以上是关于Django 模型对象和石墨烯 get_node的主要内容,如果未能解决你的问题,请参考以下文章