如何在 python 石墨烯解析器中 return json 引号前没有反斜杠
How to return json in python graphene resolver without backslashes before quotation marks
我在 python(Flask + Graphene)中有一个后端服务器,我需要 return 一个 JSON 对象,如下所示:
{
's1': "Section 1",
's2': "Section 2",
's3': "Section 3",
's4': "Section 4"
}
解析器如下所示:
questionnaire = graphene.types.json.JSONString(
description='JSON result test')
def resolve_questionnaire(self, info: graphql.ResolveInfo):
sections = {
's1': "Section 1",
's2': "Section 2",
's3': "Section 3",
's4': "Section 4"
}
print(json.dumps(sections))
return sections
并且在控制台中,我看到了 print(json.dumps(sections))
的结果,如我所料:
user-api_1 | {"s1": "Section 1", "s2": "Section 2", "s3": "Section 3", "s4": "Section 4"}
但在 GraphiQL 中,我看到所有带反斜杠的引号:
当我将 return sections
更改为 return json.dumps(sections)
时,我得到的结果如下:
问题是如何在石墨烯解析器中正确地return一个JSON对象?
我知道有 json.replace 方法可以像 一样使用,但我相信我只是 producing/passing 以错误的方式使用对象。
你的初步结果
{
"data": {
"questionnaire": "{\"s1\": \"Section 1\", \"s2\": \"Section 2\", \"s3\": \"Section 3\", \"s4\": \"Section 4\"}"
}
}
是预期的行为。毕竟,questionnaire
解析为 JSONString。由于它是一个字符串,因此必须用双引号引起来,因此必须转义其内部引号。这是根据 JSON's standards.
要使用该字符串,您必须在 data.questionnaire
对象上 运行 某种 JSON 解析器。例如,在 javascript 中,它类似于:
var data;
// Fetching logic to get the data object from your GraphQL server
var sections = JSON.parse(data.questionaire);
// Now you can access its objects
console.log(sections.s1) // Should print "Section 1" on the dev console
但是,如果sections
的键没有预先确定(sections.s5
在一种情况下可能定义但undefined 在另一个)。相反,您可能更愿意拥有一个可以迭代的数组。为此,您必须定义一个具有显式键值对的 "model"。这样做也是适合 GraphQL 的格式。例如:
import graphene
# Our new model
class Section(graphene.ObjectType):
key = graphene.String() # dictionary key
header = graphene.String() # dictionary value
# Your previous schema with modifications
class Query(graphene.ObjectType):
# questionnaire = graphene.types.json.JSONString(description='JSON result test')
# Return a list of section objects
questionnaire = graphene.List(Section)
def resolve_questionnaire(self, info: graphql.ResolveInfo):
sections = {
's1': "Section 1",
's2': "Section 2",
's3': "Section 3",
's4': "Section 4"
}
sections_as_obj_list = [] # Used to return a list of Section types
# Create a new Section object for each item and append it to list
for key, value in sections.items(): # Use sections.iteritems() in Python2
section = Section(key, value) # Creates a section object where key=key and header=value
sections_as_obj_list.append(section)
# return sections
return sections_as_obj_list
现在,如果我们 运行 查询:
query {
questionnaire {
key
header
}
}
它 returns 一个 JSON 可以迭代的数组。
{
"data" {
"questionnaire": [
{
"key": "s1",
"header": "Section 1"
},
{
"key": "s2",
"header": "Section 2"
},
{
"key": "s3",
"header": "Section 3"
},
{
"key": "s4",
"header": "Section 4"
},
]
}
}
您可以将 JSON 类型子类化并替换序列化方法:
class Any(JSON):
@staticmethod
def serialize(dt):
return dt
然后代替
questionnaire = Field(JSON)
写
questionnaire = Field(Any)
是的,这确实打破了 GraphQL 的严格类型精神,但如果那是你想做的,那就有办法了。请注意,这是一个仅输出的 hack——它不允许您接受任意结构作为参数。
另一种方法,return一个json/字典的数组。
我试图从模型混合 属性 属性中 return json。
基本上是任何类型(注意:失去打字的好处),帮助我从字典列表中 return json:
import graphene
from graphene import relay, Scalar
from graphene_django import DjangoObjectType
class DictType(Scalar):
@staticmethod
def serialize(dt):
return dt
@staticmethod
def parse_literal(node):
return node
@staticmethod
def parse_value(value):
return value
节点本身基于一个包含混合的模型:
class InvoiceFileNode(DjangoObjectType):
signed_url = graphene.String()
variable_files = graphene.List(of_type=DictType)
class Meta:
model = InvoiceFile
interfaces = (relay.Node,)
filter_fields = []
only_fields = (
"id",
"created",
"signed_url",
"variable_files",
)
def resolve_signed_url(self, *args, **kwargs):
# @property access from FileMixin
return self.signed_url
def resolve_openable_signed_url(self, *args, **kwargs):
# @property access from FileMixin
return self.openable_signed_url
下面的 mixin 是我试图得到的 returned,但是使用 JSONString
的 of_type
将字典序列化为 json 字符串:
class FileMixin(object):
@property
def signed_url(self) -> str:
return get_signed_url(self.file)
@property
def variable_files(self) -> str:
sizes = []
for s in [128, 240, 720]:
item = {"width": s}
urls = []
for n in [1,2,3]:
urls.append(get_sized_url(self.file, n))
item["urls"] = urls
sizes.append(item)
return sizes
class InvoiceFile(Models, FileMixin):
created = DateTimeField()
file = CharField()
我遇到了 return 类似的问题:
[{"width": 123, "stuff": [{"more": "stuff"}]}}
注意
如果字典 returned 包含任何类型的函数或对象等,这可能不起作用
在我的例子中,我有一个名为(详细信息)的 JSON 列。
from graphene.types.scalars import Scalar
class ObjectField(Scalar):
''' convert the Json String into Json '''
@staticmethod
def serialize(dt):
return dt
@staticmethod
def parse_literal(node):
return node.value
@staticmethod
def parse_value(value):
return value
class CustomDiseaseFactNode(graphene.Node):
class Meta:
name = 'diseaseFactNode'
@staticmethod #this class used to get the primary key object id
def to_global_id(type, id):
return id
Call the JSONScalar from your object class
class DiseaseFactNode(SQLAlchemyObjectType):
"""DiseaseFact node."""
class Meta:
model = DiseaseFact
interfaces = (CustomDiseaseFactNode,)
details = JSONScalar()
石墨烯现在有一个 GenericScalar
类型。
from graphene.types import generic
...
errors = generic.GenericScalar()
我在 python(Flask + Graphene)中有一个后端服务器,我需要 return 一个 JSON 对象,如下所示:
{
's1': "Section 1",
's2': "Section 2",
's3': "Section 3",
's4': "Section 4"
}
解析器如下所示:
questionnaire = graphene.types.json.JSONString(
description='JSON result test')
def resolve_questionnaire(self, info: graphql.ResolveInfo):
sections = {
's1': "Section 1",
's2': "Section 2",
's3': "Section 3",
's4': "Section 4"
}
print(json.dumps(sections))
return sections
并且在控制台中,我看到了 print(json.dumps(sections))
的结果,如我所料:
user-api_1 | {"s1": "Section 1", "s2": "Section 2", "s3": "Section 3", "s4": "Section 4"}
但在 GraphiQL 中,我看到所有带反斜杠的引号:
当我将 return sections
更改为 return json.dumps(sections)
时,我得到的结果如下:
问题是如何在石墨烯解析器中正确地return一个JSON对象?
我知道有 json.replace 方法可以像
你的初步结果
{
"data": {
"questionnaire": "{\"s1\": \"Section 1\", \"s2\": \"Section 2\", \"s3\": \"Section 3\", \"s4\": \"Section 4\"}"
}
}
是预期的行为。毕竟,questionnaire
解析为 JSONString。由于它是一个字符串,因此必须用双引号引起来,因此必须转义其内部引号。这是根据 JSON's standards.
要使用该字符串,您必须在 data.questionnaire
对象上 运行 某种 JSON 解析器。例如,在 javascript 中,它类似于:
var data;
// Fetching logic to get the data object from your GraphQL server
var sections = JSON.parse(data.questionaire);
// Now you can access its objects
console.log(sections.s1) // Should print "Section 1" on the dev console
但是,如果sections
的键没有预先确定(sections.s5
在一种情况下可能定义但undefined 在另一个)。相反,您可能更愿意拥有一个可以迭代的数组。为此,您必须定义一个具有显式键值对的 "model"。这样做也是适合 GraphQL 的格式。例如:
import graphene
# Our new model
class Section(graphene.ObjectType):
key = graphene.String() # dictionary key
header = graphene.String() # dictionary value
# Your previous schema with modifications
class Query(graphene.ObjectType):
# questionnaire = graphene.types.json.JSONString(description='JSON result test')
# Return a list of section objects
questionnaire = graphene.List(Section)
def resolve_questionnaire(self, info: graphql.ResolveInfo):
sections = {
's1': "Section 1",
's2': "Section 2",
's3': "Section 3",
's4': "Section 4"
}
sections_as_obj_list = [] # Used to return a list of Section types
# Create a new Section object for each item and append it to list
for key, value in sections.items(): # Use sections.iteritems() in Python2
section = Section(key, value) # Creates a section object where key=key and header=value
sections_as_obj_list.append(section)
# return sections
return sections_as_obj_list
现在,如果我们 运行 查询:
query {
questionnaire {
key
header
}
}
它 returns 一个 JSON 可以迭代的数组。
{
"data" {
"questionnaire": [
{
"key": "s1",
"header": "Section 1"
},
{
"key": "s2",
"header": "Section 2"
},
{
"key": "s3",
"header": "Section 3"
},
{
"key": "s4",
"header": "Section 4"
},
]
}
}
您可以将 JSON 类型子类化并替换序列化方法:
class Any(JSON):
@staticmethod
def serialize(dt):
return dt
然后代替
questionnaire = Field(JSON)
写
questionnaire = Field(Any)
是的,这确实打破了 GraphQL 的严格类型精神,但如果那是你想做的,那就有办法了。请注意,这是一个仅输出的 hack——它不允许您接受任意结构作为参数。
另一种方法,return一个json/字典的数组。
我试图从模型混合 属性 属性中 return json。
基本上是任何类型(注意:失去打字的好处),帮助我从字典列表中 return json:
import graphene
from graphene import relay, Scalar
from graphene_django import DjangoObjectType
class DictType(Scalar):
@staticmethod
def serialize(dt):
return dt
@staticmethod
def parse_literal(node):
return node
@staticmethod
def parse_value(value):
return value
节点本身基于一个包含混合的模型:
class InvoiceFileNode(DjangoObjectType):
signed_url = graphene.String()
variable_files = graphene.List(of_type=DictType)
class Meta:
model = InvoiceFile
interfaces = (relay.Node,)
filter_fields = []
only_fields = (
"id",
"created",
"signed_url",
"variable_files",
)
def resolve_signed_url(self, *args, **kwargs):
# @property access from FileMixin
return self.signed_url
def resolve_openable_signed_url(self, *args, **kwargs):
# @property access from FileMixin
return self.openable_signed_url
下面的 mixin 是我试图得到的 returned,但是使用 JSONString
的 of_type
将字典序列化为 json 字符串:
class FileMixin(object):
@property
def signed_url(self) -> str:
return get_signed_url(self.file)
@property
def variable_files(self) -> str:
sizes = []
for s in [128, 240, 720]:
item = {"width": s}
urls = []
for n in [1,2,3]:
urls.append(get_sized_url(self.file, n))
item["urls"] = urls
sizes.append(item)
return sizes
class InvoiceFile(Models, FileMixin):
created = DateTimeField()
file = CharField()
我遇到了 return 类似的问题:
[{"width": 123, "stuff": [{"more": "stuff"}]}}
注意
如果字典 returned 包含任何类型的函数或对象等,这可能不起作用
在我的例子中,我有一个名为(详细信息)的 JSON 列。
from graphene.types.scalars import Scalar
class ObjectField(Scalar):
''' convert the Json String into Json '''
@staticmethod
def serialize(dt):
return dt
@staticmethod
def parse_literal(node):
return node.value
@staticmethod
def parse_value(value):
return value
class CustomDiseaseFactNode(graphene.Node):
class Meta:
name = 'diseaseFactNode'
@staticmethod #this class used to get the primary key object id
def to_global_id(type, id):
return id
Call the JSONScalar from your object class
class DiseaseFactNode(SQLAlchemyObjectType):
"""DiseaseFact node."""
class Meta:
model = DiseaseFact
interfaces = (CustomDiseaseFactNode,)
details = JSONScalar()
石墨烯现在有一个 GenericScalar
类型。
from graphene.types import generic
...
errors = generic.GenericScalar()