Quantcast
Channel: CodeSection,代码区,Python开发技术文章_教程 - CodeSec
Viewing all articles
Browse latest Browse all 9596

GraphQL+Django提供基本API

$
0
0

GraphQL 是Facebook去年开源的一套数据查询语言,对于大型系统,GraphQL提供一种灵活的访问通用数据的方式。当时正好有一个项目,需要前端调用后台的数据(Postgresql)实现图表展示,我就从Postgresql里把数据导出成JSON文件,前端直接用GraphQL获取自己需要的数据,后台也省掉了制作API、写SQL的工作,运行至今基本稳定。

当时GraphQL还没有针对Django的modules,前两个月发布了 graphene-django ,做的事情不多,但可以搭配其他插件例如django-filters来实现更丰富的查询,基本能满足需求。GraphQL的优势在于查询语句的通用性和易读性,相比REST架构来说时间较短还不够成熟,如果是复杂需求后台的开发量仍然不小,现阶段在生产环境用Django做一个API服务还是rest framework等成熟的方案会更好。本文实现一个针对Django自带的User Model的简单API。

环境:

Django 1.10.4

graphene-django-1.2.0

Setup

安装graphene-django,如果是新建Django项目,创建后执行migrate创建表,再创建admin用户:

pip install graphene-django

django-admin startproject dmyz

cd dmyz

python manage.py migrate

python manage.py createsuperuser

编辑 settings.py ,将graphene-django加入INSTALLED_APPS:

INSTALLED_APPS = ( # ... 'graphene_django', )

再编辑 urls.py ,导入GraphQLView,加上graphql的设置:

from graphene_django.viewsimport GraphQLView urlpatterns = [ # ... url(r'^graphql', GraphQLView.as_view(graphiql=True)), ]

执行runserver,这时候访问/graphql会报错,显示没有提供schema。

Schema

在dmyz目录中新建 schema.py 文件,目录结构如下:

dmyz

├── db.sqlite3

├── dmyz

│ ├── __init__.py

│ ├── schema.py

│ ├── settings.py

│ ├── urls.py

│ └── wsgi.py

└── manage.py

编辑 schema.py 文件,导入DjangoObjectType和graphene,处理django自带的User Model,代码如下:

from django.contrib.auth.modelsimport User as UserModel from graphene_djangoimport DjangoObjectType import graphene class User(DjangoObjectType): class Meta: model = UserModel class Query(graphene.ObjectType): users = graphene.List(User) @graphene.resolve_only_args def resolve_users(self): return UserModel.objects.all() schema = graphene.Schema(query=Query)

最后编辑 settings.py ,加上配置:

GRAPHENE = { 'SCHEMA': 'dmyz.schema.schema' }

现在重新访问/graphql,可以看到自带的前端界面,在左上角文本框中输入:

{ users { username email } }

运行(点击上方:arrow_forward:按钮)返回admin用户的username和email。右侧的Docs会显示Query信息,下划线命名也会自动转成驼峰命名。

查询语句完整格式是 query 名称{} ,上面的查询语句省掉了 query ,因为GraphQL默认会作为 query 语句执行,如果是 mutation 就需要加上了。关于查询语句可以参考官方文档: http://graphql.org/learn/queries/


GraphQL+Django提供基本API
Schema & Type & Field

无论后台是Python还是Nodejs,查询语句都是一样的,但不同语言对Schema的实现方式不同。Schema定义数据的呈现结构,包含各种Types,其中Query和Mutation是两个特殊的Type,Type通过Fields指定返回的数据字段。以之前的代码为例,代码中定义了Type(Query)和Fields(users),指定resolve来处理数据。

Filter

先增加一个测试用户,在后台添加或者执行:

python manage.py shell -c “from django.contrib.auth.models import User;User.objects.create_user(username=’dmyz’,email=’admin@dmyz.org’,password=’dmyz.org’)”

执行之前的查询语句会返回两条记录。修改 schema.py 的修改Query:

class Query(graphene.ObjectType): users = graphene.List(User, id=graphene.Int()) #指定id字段作为查询参数 #@graphene.resolve_only_args 注释装饰器,接收args参数 def resolve_users(self, args, context, info): if args == {}: #如果没有参数就返回所有结果 return UserModel.objects.all() return UserModel.objects.filter(pk=args.get('id')) #否则返回过滤后的结果 schema = graphene.Schema(query=Query)

执行新的查询语句,指定id:

query userId{users(id: 2) {id,username,email}}

新的查询语句用逗号分隔字段,增加了名字,执行后只返回id=2的用户:

curl “http://127.0.0.1:8000/graphql?query=query%20userId%7Busers(id%3A%202)%20%7Bid%2Cusername%2Cemail%7D%7D&operationName=userId” | python -m json.tool

{

“data”: {

“users”: [

{

“id”: “2”,

“username”: “dmyz”,

“email”: “admin@dmyz.org”

}

]

}

}

Mutation

先继承graphene.Mutation创建一个类,定义输入的参数,再处理成ObjectType传递给Schema:

class CreateUser(graphene.Mutation): class Input: username = graphene.String() password = graphene.String() email = graphene.String() ok = graphene.Boolean() user = graphene.Field(lambda: User) def mutate(self, args, content, info): user = User(username=args.get('username')) ok = True return CreateUser(ok=ok, user=user) class Mutation(graphene.ObjectType): create_user = CreateUser.Field() schema = graphene.Schema(query=Query, mutation=Mutation)

查询语句必须申明是 mutation ,传入Input中定义的字段,还要定义返回的内容:

mutation { createUser(username: "graphql", password: "test") { ok user { username } } }

执行后返回数据:

{ "data": { "createUser": { "ok": true, "user": { "username": "graphql" } } } }


Viewing all articles
Browse latest Browse all 9596

Trending Articles