python graphql_详解Python Graphql
前言
很高兴现在接手的项目让我接触到了Python Graphql,百度上对其介绍相对较少也不够全面,几乎没有完整的中文文档,所以这边也借此机会学习一下Graphql。
什么是Graphql呢?
Graphql是一个API查询语言,其数据由服务器上的一个Scheme提供,其查询返回的数据依赖请求的时候用户需要的精确数据。列如用户只需要一个name字段,服务器也只返回name的值。
参考
Hello Word 入门
先看下面一个例子,查询语句为{ hello(name:"gaojiayi") } 定义了要查询的入口,以及传入的参数。
from graphene importObjectType, String, SchemaclassQuery(ObjectType):"""定义一个字符串属性域hello 且有一个字符串参数为name,设置name的默认"""hello= String(name = String(default_value="gaojy",required=True))#resolve_hello定义了上面hello的实现,并返回查询结果
#一般resolve需要加上固定前缀resolve_
@staticmethoddefresolve_hello(root,info,name):return f"hello word -- {name}"schema= Schema(query=Query)if __name__ == '__main__':
query_string= '''{ hello(name:"gaojiayi") }'''result=schema.execute(query_string)print(result.data['hello'])
Graphql中的Types
Scheme
下面定义了一个Scheme,其中MyRootQuery,MyRootMutation,MyRootSubscription都是继承了graphene .objectType,但是不同之处在于query定义了查询数据的入口,而mutation用来数据改变或者数据恢复,而subscription是用来实时呈现数据的变化给client。type是用来指定返回数据的精确类型,列如返回的数据是一个interface,但是有多个类型继承了该interface,这时候需要指定一个具体的实现来返回给client。
my_schema =Schema(
query=MyRootQuery,
mutation=MyRootMutation,
subscription=MyRootSubscription,
type=[SomeExtraObjectType,]
)
另外查询字符串默认为驼峰命名,列如
from graphene importObjectType, String, SchemaclassQuery(ObjectType):
other_name= String(name='_other_Name')
@staticmethoddefresolve_other_name(root, info):return "test CamelCase"schema= Schema(query=Query)if __name__ == '__main__':#查询数默认使用otherName,此处用了别名。
result = schema.execute('''{_other_Name}''')print(result.data['_other_Name'])
如果关闭默认驼峰命名方式,则可以在定义scheme的时候加上auto_camelcase=False
my_schema = Schema(
auto_camelcase=False)
scalars
scalars type可以理解为用来定义Field,它可以传入以下几种可选参数,例如
other_name = String(name='_other_Name',required=True,description="",deprecation_reason="",defalut_value=Any)
常见的基本saclars type有如下几个:
graphene.String
graphene.Int
graphene.Float
graphene.Boolean
graphene.ID
graphene.types.datetime.Date
graphene.types.datetime.DateTime
graphene.types.datetime.Time
graphene.types.json.JSONString
View Code
saclars type的挂载在objectType,interface,Mutation中的field域中。
classPerson(graphene.ObjectType):
name=graphene.String()#Is equivalent to:
classPerson(graphene.ObjectType):
name= graphene.Field(graphene.String)
View Code
Lists and Non-Null
Non-Null
importgrapheneclassCharacter(graphene.ObjectType):
name= graphene.String(required=True)#等价于 即返回的数据如果name=null,则会报错
classCharacter(graphene.ObjectType):
name= graphene.String(required=True)
Lists
importgrapheneclassCharacter(graphene.ObjectType):#appears_in表示为一个非null元素的列表
appears_in = graphene.List(graphene.NonNull(graphene.String))
ObjectType
objectType是在scheme中用来定义Fields之间联系以及数据流转的python类,每一个obejctType属性表示一个Field,每个Field定义一个resolve方法用来获取数据,如果没有定义,则使用一个默认的resolver。
接下来看一个例子。
from graphene importObjectType, String, SchemaclassQuery(ObjectType):
@staticmethoddefresolve_hello(parent,info,name):return f"hello word -- {name}"
上面的resolve_hello有三个参数,分别是parent,info,name
1 parent通常用来获取objectType内的其他field的值,而在根query中默认为None,看下面的事例,当OjectType的Field为saclar type,则parent不会再向下传递。
classPerson(ObjectType):
full_name=String()defresolve_full_name(parent, info):return f"{parent.first_name} {parent.last_name}"
classQuery(ObjectType):
me=Field(Person)defresolve_me(parent, info):#returns an object that represents a Person
#这里的parent为None
return get_human(name="Luke Skywalker")
View Code
2 info表示请求的上下文,可以在查询语中添加context
3 name表示请求时带的参数,可以参考hello word事例,如有多个参数可形参**kwargs
from graphene importObjectType, StringclassQuery(ObjectType):
hello= String(required=True, name=String())def resolve_hello(parent, info, **kwargs):#name 为None 则name = World
name = kwargs.get('name', 'World')return f'Hello, {name}!'
View Code
4 默认resolver:列如一个objectType的field都没有指定队友的resolve,那么对象默认会序列化一个字典。
PersonValueObject = namedtuple('Person', 'first_name', 'last_name')classPerson(ObjectType):
first_name=String()
last_name=String()classQuery(ObjectType):
me=Field(Person)
my_best_friend=Field(Person)defresolve_me(parent, info):#always pass an object for `me` field
#{"firstName": "Luke", "lastName": "Skywalker"}
return PersonValueObject(first_name='Luke', last_name='Skywalker')
View Code
5 meta 类:用于objectType的配置
Enum
classEpisode(graphene.Enum):
NEWHOPE= 4EMPIRE= 5JEDI= 6@propertydefdescription(self):if self ==Episode.NEWHOPE:return 'New Hope Episode'
return 'Other episode'
classQuery(ObjectType):
desc1=String(
v=Argument(Episode, default_value=Episode.NEWHOPE.value),
description='default value in schema is `4`, which is not valid. Also, awkward to write.')
@staticmethoddefresolve_desc1(parent, info,v):return f'argument: {v!r}'
#使用下面的方式可以将python类型的enum转化成saclars类型
graphene.Enum.from_enum(
AlreadyExistingPyEnum,
description=lambda v: return 'foo' if v == AlreadyExistingPyEnum.Foo else 'bar')
View Code
Interfaces
顾名思义,接口,其他的obectType可以继承接口,示例如下
importgrapheneclassCharacter(graphene.Interface):
id= graphene.ID(required=True)
name= graphene.String(required=True)
friends= graphene.List(lambda: Character)#继承Character
classHuman(graphene.ObjectType):classMeta:
interfaces=(Character, )
starships=graphene.List(Starship)
home_planet=graphene.String()#继承Character
classDroid(graphene.ObjectType):classMeta:
interfaces=(Character, )
primary_function=graphene.String()classQuery(graphene.ObjectType):#返回的类型是Character
hero =graphene.Field(
Character,
required=True,
episode=graphene.Int(required=True)
)defresolve_hero(root, info, episode):#Luke is the hero of Episode V
if episode == 5:return get_human(name='Luke Skywalker')return get_droid(name='R2-D2')#对于返回数据具体类型,可以在type属性中列举
schema = graphene.Schema(query=Query, types=[Human, Droid])
View Code
另外scheme中如果没有指定type,会报错
"Abstract type Character must resolve to an Object type at runtime for field Query.hero ..."
可以在interface中重写resolve_type方法
classCharacter(graphene.Interface):
id= graphene.ID(required=True)
name= graphene.String(required=True)#返回数据的时候,可以转换成具体的数据类型
@classmethoddefresolve_type(cls, instance, info):if instance.type == 'DROID':returnDroidreturn Human
Union
该scalars type用来组合多个ObjectType,列如
importgrapheneclassHuman(graphene.ObjectType):
name=graphene.String()
born_in=graphene.String()classDroid(graphene.ObjectType):
name=graphene.String()
primary_function=graphene.String()classStarship(graphene.ObjectType):
name=graphene.String()
length=graphene.Int()#SearchResult组合了Human Droid Starship所有的Fields
classSearchResult(graphene.Union):classMeta:
types= (Human, Droid, Starship)
View Code
Mutations
如果说query是一个http get请求,那么Mutations可以看做是一个http post put请求。
def Mutate作为一个特殊的resover,当被调用的时候意在改变Mutation内的数据。
看下面一个操作示例
#具体的操作类
classCreatePerson(graphene.Mutation):#请求提交的参数,同样需要传递到mutate中
classArguments:
name=graphene.String()
ok=graphene.Boolean()
person=graphene.Field(Person)defmutate(root, info, name):
person= Person(name=name)
ok=True#可执行具体的业务逻辑 包括写表 发消息等等
return CreatePerson(person=person, ok=ok)#Mutation
classMyMutations(graphene.ObjectType):
create_person=CreatePerson.Field()#指定mutation MyMutations
schema = Schema(query=Query,mutation=MyMutations)
执行结果如下:
小结
技术本身就是为业务服务,读者会问Graphql究竟可以使用在哪些业务场景呢?
官方有这么一句话ask exactly what you want.如果一个前端的接口只需要返回部分数据,而另一个前端接口也只需要返回部分数据,这两份数据有可能有交集,也可能没有。传统的做法可能需要开发两个接口或者一个接口内不断的if else来根据前端的具体场景去过滤某些数据。使用Graphql能够根据client指定需要哪些参数,后端scheme返回哪些参数,而后端只需要一个API可以查询到数据全集,Graphql可以自动完成数据解析,封装,过滤操作。
python graphql_详解Python Graphql相关推荐
- python join_详解Python中的join()函数的用法
函数:string.join() Python中有join()和os.path.join()两个函数,具体作用如下: join(): 连接字符串数组.将字符串.元组.列表中的元素以指定的字符(分隔符) ...
- python getattr_详解 Python 的二元算术运算,为什么说减法只是语法糖?
原题 | Unravelling binary arithmetic operations in Python 作者 | Brett Cannon 译者 | 豌豆花下猫("Python猫&q ...
- python多线程详解 Python 垃圾回收机制
文章目录 python多线程详解 一.线程介绍 什么是线程 为什么要使用多线程 总结起来,使用多线程编程具有如下几个优点: 二.线程实现 自定义线程 守护线程 主线程等待子线程结束 多线程共享全局变量 ...
- python expandtabs_详解Python中expandtabs()方法的使用
详解Python中expandtabs()方法的使用 expandtabs()方法返回制表符,即该字符串的一个副本. '\t'已经使用的空间,可选择使用给定的tabsize(默认8)扩展. 语法 以下 ...
- python讲解-详解python中@的用法
python中@的用法 @是一个装饰器,针对函数,起调用传参的作用. 有修饰和被修饰的区别,"@function"作为一个装饰器,用来修饰紧跟着的函数(可以是另一个装饰器,也可以是 ...
- python括号详解,Python如何省略括号方法详解
Python如何省略括号方法详解 在Python语言中最常见的括号有三种,分别是:小括号().中括号[].花括号{}:其作用也不相同,分别用来代表不同的Python基本内置数据类型. 1.Python ...
- python enumerate_详解 Python 的 enumerate 函数
Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发. 你应该在何时何地,如何使用内置的 enumerate() 函数来写出更加简洁.更加具有 Python 范儿 ...
- python include_tag_详解Python的Django框架中inclusion_tag的使用
另外一类常用的模板标签是通过渲染 其他 模板显示数据的. 比如说,Django的后台管理界面,它使用了自定义的模板标签来显示新增/编辑表单页面下部的按钮. 那些按钮看起来总是一样的,但是链接却随着所编 ...
- python def函数报错详解_【python】详解python函数定义 def()与参数args、可变参数*args、关键参数**args使用实例...
Python内置了很多函数,可以直接调用.Python内置的函数可以通过官方文档查看.也可以通过help()查看帮助信息.函数名是指向函数对象的引用,把函数名赋给变量,相当于给函数起了别名. 1. 定 ...
最新文章
- QT的Q3DScatter类的使用
- 【技术改造】电商系统用户模块集成Feign-1
- 姚期智:量子计算只剩最后一里路;霍金:人类最好移民外太空
- oracle 监听报错,解决Oracle监听服务报错
- 大数据技术如何实现核心价值
- 基于统计学的商务与经济数据分析知识
- 不仅仅是游戏,王者荣耀如何突破次元壁?
- IDEA “Cannot resolve symbol” 解决办法
- 微信答题小程序开发功能概述
- 电脑上的PDF文件太大了怎么办?
- python实现离散型变量分组统计
- 微博服务器瘫痪容易修复吗,微博服务器九次瘫痪,还有一个竟然连崩四回,程序员:放过我吧!...
- 父进程和子进程之间的关系
- python时间索引_Python时间戳作为索引
- 菜鸟网html dom对象,JavaScript学习指南
- 三种爱心代码html(文本文档即可实现)
- jQuery——常用方法
- 自动弹窗被拦截 html,chrome拦截弹窗问题的两种解决方式
- 脑分享 | 脑结构、脑工作原理最详细图解
- 数学建模学习(87):正余弦优化算法(SCA)对多元函数寻优