Object types、 scalars和 enums 是可以在Graphene中定义的唯一类型。但是,当在schema的其他部分或查询变量声明中使用类型时,可以应用其他类型修饰符来影响这些值的验证。
import graphene
class Man(graphene.ObjectType):
name = graphene.NonNull(graphene.String)
使用一个String类型,并通过使用NonNull类包装它来将其标记为Non-Null。意味着总是为这个字段返回一个非null值
同时也等效于 :
import graphene
# 推荐此方法,简单明了
class Man(graphene.ObjectType):
name = graphene.String(required=True)
import graphene
class Man(graphene.ObjectType):
name_in = graphene.List(graphene.String)
使用类型修饰符List将类型标记为列表,这表明字段将返回该类型的列表。它对参数的作用相同,验证步骤需要该值的列表。
默认情况下,列表中的项将被视为可以为null。若要定义不包含任何可为null的列表,需要将类型标记为NonNull。例如:
import graphene
class Man(graphene.ObjectType):
name_in = graphene.List(graphene.NonNull(graphene.String))
ObjectType是用于定义Schema
中Fields
之间的关系及其数据检索方式的构建块
每个ObjectType都是从graphene.ObjectType继承的
ObjectType的每个属性都表示一个字段
每个字段都有一个resolve方法来获取数据(或默认resolve)
from graphene import ObjectType, String
class Person(ObjectType):
full_name = String()
def resolve_full_name(parent, info):
return "lu wei"
ObjectType定义字段first_name、last_name和full_name。每个字段都被指定为一个类属性,并且每个属性都映射到一个字段。数据由full_name字段的resolve_full_name解析程序方法获取,其他字段为默认解析程序获取
Resolver是一种通过获取Schema中字段的数据来返回查询的方法,它是延迟执行的,因此查询中如果不包含字段,则不会执行解析程序
ObjectType上的每个字段都应该有一个相应的解析程序方法来获取数据。格式必须为 resolve_xxx 如上面的resolve_full_name
每个Resolver都采用以下参数:
parent:用于解析大多数字段的值的父值对象(父对象)
info:用于查询和Schema元信息以及每个请求的上下文
**kwargs:字段上定义的参数(**kwargs)
解析程序方法(父级)的第一个参数是从父字段的解析程序返回的值对象。如果没有父字段,例如根查询字段,则父字段的值将设置为执行查询时配置的root_value(默认为None)
如果有一个Person类型的Schema和根查询上的字段, 如下:
from graphene import ObjectType, String, Schema, Field
class Person(ObjectType):
first_name = String()
last_name = String()
full_name = String()
def resolve_full_name(parent, info):
return f"{parent.first_name} {parent.last_name} cool"
person = Person(
first_name="lu",
last_name="wei",
full_name="lu wei"
)
class Query(ObjectType):
me = Field(Person)
def resolve_me(parent, info):
return person
# 执行查询
schema = Schema(query=Query)
query_string = "{ me { fullName } }"
result = schema.execute(query_string)
print(result.data)
查询的流程如下:
每个resolver返回下一个Parent Value Object(父对象),用于执行链中的解析器。如果字段是scalar类型,则该值将被序列化并在响应中返回。否则,在解析ObjectType等复合类型时,该值将作为下一个Parent value Object(父对象)向前传递
info参数
:引用有关当前GraphQL查询执行的元信息(字段、模式、解析查询等)
访问每个请求上下文,该上下文可用于存储用户身份验证、数据加载器实例或任何其他有助于解决查询的内容
字段定义的任何参数都将作为关键字(值)参数传递给resolver函数。例如:
from graphene import ObjectType, Field, String
class Person(ObjectType):
first_name = String()
last_name = String()
full_name = String()
def resolve_full_name(parent, info):
return f"{parent.first_name} {parent.last_name} cool"
person = Person(
first_name="lu",
last_name="wei",
full_name="lu wei"
)
class Query(ObjectType):
last_name = Field(Person, name=String(required=True)) # 此时name为关键字参数
def resolve_last_name(parent, info, name):
return person
'''
query {
lastName(name: "lu wei") {
firstName
lastName
}
}
'''
注意:如果定义的参数与内置的参数名必须一样时就需要用
args 包住`:
from graphene import ObjectType, Field, String
class Query(ObjectType):
last_name = String(args={'description': String()}) # description本身为内置参数,如果值参数名称一样,需要使用args传递
def resolve_last_name(parent, info, description):
...
graphene所有的resolve方法都被隐式地视为静态方法。第一个参数在执行时不是self。是Parent(父对象)
from graphene import ObjectType, String
class Person(ObjectType):
first_name = String()
last_name = String()
# 以下两者相同
@staticmethod
def resolve_first_name(parent, info):
...
def resolve_last_name(parent, info):
...
如果没有为Field定义resolve方法,Graphene将提供默认的解析程序
如果父对象是字典,则resolve将查找与字段名称匹配的字典键。否则,resolve将从与字段名称匹配的父值对象中获取属性
from collections import namedtuple
from graphene import ObjectType, String, Field, Schema
PersonValueObject = namedtuple("Person", ["first_name", "last_name"]) # 定义一个元祖
class Person(ObjectType):
first_name = String()
last_name = String()
class Query(ObjectType):
me = Field(Person)
my_friend = Field(Person)
def resolve_me(parent, info):
return PersonValueObject(first_name="lu", last_name="wei") # 传递元祖 上面Person默认解析器会从中拿取对应的属性
def resolve_my_friend(parent, info):
return {"first_name": "lu1", "last_name": "wei1"} # 传递字典 上面Person默认解析器会从中拿取对应的键
schema = Schema(query=Query)
result = schema.execute('''
{
me { firstName lastName }
myFriend { firstName lastName }
}
''')
如果字段定义了一个参数且不为null,那么它根本不会传递给解析程序函数
from graphene import ObjectType, String
class Query(ObjectType):
hello = String(required=True, name=String())
def resolve_hello(parent, info, name):
return name if name else 'World'
# 当没有值时, name 不会传递到 resolve 解析器 所以在解析器中会出现找不到name的错误
# TypeError: resolve_hello() missing 1 required positional argument: 'name'
# 正确的做法为在解析器中设定一个默认值
class Query(ObjectType):
hello = String(required=True, name=String())
def resolve_hello(parent, info, name='World'):
return f'Hello, {name}!'
# or
class Query(ObjectType):
hello = String(required=True, name=String())
def resolve_hello(parent, info, **kwargs):
name = kwargs.get('name', 'World')
return f'Hello, {name}!'
# or (推荐)
class Query(ObjectType):
hello = String(
required=True,
name=String(default_value='World')
)
def resolve_hello(parent, info, name):
return f'Hello, {name}!'
也可以在外部定义解析程序,只需在字段中指定即可
from graphene import ObjectType, String
def resolve_full_name(person, info):
return f"{person.first_name} {person.last_name}"
class Person(ObjectType):
first_name = String()
last_name = String()
full_name = String(resolver=resolve_full_name)
作为值对象的实例
graphene对象类型也可以作为值对象。因此,在前面的示例中,可以使用Person来捕获ObjectType的每个字段的数据
peter = Person(first_name='lu', last_name='wei')
peter.first_name # prints "lu"
peter.last_name # prints "wei"
类型名称
默认情况下,类型名称与定义ObjectType的类名相同,可以通过在Meta类上设置name属性来更改:
from graphene import ObjectType
class MySong(ObjectType):
class Meta:
name = 'Song'
Description
ObjectType的schema描述可以在Python对象或Meta内部类上设置
from graphene import ObjectType
class MySong(ObjectType):
''' 这是一个schema '''
class Meta:
description = '这是一个schema'
接口和可能的类型
在Meta的interfaces中设置接口,以指定此对象实现的GraphQL接口。
提供possible_types可以使graphene解决不明确的类型
from graphene import ObjectType, Node
Song = namedtuple('Song', ('title', 'artist'))
class MySong(ObjectType):
class Meta:
interfaces = (Node, )
possible_types = (Song, )
下篇继续介绍interfaces与Mutations的用法