安装
1
| pip install graphene-django
|
配置
1
2
3
4
5
6
7
8
9
| # settings.py
INSTALLED_APPS = [
# ...
'graphene_django', # 添加组件
]
GRAPHENE = { 'SCHEMA': '路径.schema' } # 这里schema为文件内的变量, 对应 schema = graphene.Schema(...) 后面有说明
|
路由
1
2
3
4
5
6
7
8
9
10
11
| # urls.py
from django.urls import path
from graphene_django.views import GraphQLView
from .schemas import schema
urlpatterns = [
path('graphql/', GraphQLView.as_view(graphiql=True, schema=schema)),
]
|
schemas
1
2
3
4
5
6
7
8
| # schemas.py
import graphene
class Query(graphene.ObjectType):
hello = graphene.String(default_value="Hi!")
schema = graphene.Schema(query=Query) # GRAPHENE['SCHEMA'] 配置对应该文件的地址和变量名
|
验证
启动服务后访问: http://localhost:8000/graphql/#query=%7B%0A%20%20hello%0A%7D%0A
CSRF
去除CSRF保护(非必要配置)
1
2
3
4
5
6
7
8
9
10
11
| # urls.py
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from graphene_django.views import GraphQLView
urlpatterns = [
# ...
path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True))),
]
|
基础用法
模型定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # cookbook/ingredients/models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Ingredient(models.Model):
name = models.CharField(max_length=100)
notes = models.TextField()
category = models.ForeignKey(
Category, related_name="ingredients", on_delete=models.CASCADE
)
def __str__(self):
return self.name
|
注意: 别忘记注册APP和迁移表结构
查询定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| # cookbook/schema.py
import graphene
from graphene_django import DjangoObjectType
from cookbook.ingredients.models import Category, Ingredient # 你的模型(表)
class CategoryType(DjangoObjectType):
class Meta:
model = Category
fields = ("id", "name", "ingredients") # 可供查询的字段
class IngredientType(DjangoObjectType):
class Meta:
model = Ingredient
fields = ("id", "name", "notes", "category")
class Query(graphene.ObjectType):
all_ingredients = graphene.List(IngredientType)
category_by_name = graphene.Field(CategoryType, name=graphene.String(required=True))
def resolve_all_ingredients(root, info):
# We can easily optimize query count in the resolve method
return Ingredient.objects.select_related("category").all()
def resolve_category_by_name(root, info, name):
try:
return Category.objects.get(name=name)
except Category.DoesNotExist:
return None
schema = graphene.Schema(query=Query)
|
这里有个规则是 Query.节点
则需要创建方法 resolve_节点
的方法来编写执行过程, 这一点与 graphene 的设定一致.
普通查询
1
2
3
4
5
6
| query {
allIngredients {
id
name
}
}
|
结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| {
"data": {
"allIngredients": [
{
"id": "1",
"name": "Eggs"
},
{
"id": "2",
"name": "Milk"
},
{
"id": "3",
"name": "Beef"
},
{
"id": "4",
"name": "Chicken"
}
]
}
}
|
条件查询
1
2
3
4
5
6
7
8
9
10
| query {
categoryByName(name: "Dairy") {
id
name
ingredients {
id
name
}
}
}
|
结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| {
"data": {
"categoryByName": {
"id": "1",
"name": "Dairy",
"ingredients": [
{
"id": "1",
"name": "Eggs"
},
{
"id": "2",
"name": "Milk"
}
]
}
}
}
|
这时可以发现 graphene-django
模块帮我们完成了 Django 模型与 graphene 的信息对接, 使得查询配置变得极其简单快捷.
进阶
进阶教程请直接参考文档.
常见错误
转换失败
Exception: Don't know how to convert the Django field demo.TestModel1.tags (<class 'taggit.managers.TaggableManager'>)
这个错误是模型定义时候使用了特殊的字段, 导致的字段类型未被识别而引发的错误, 首先可以创建一个 标量, 用于处理字段的转换过程, 然后注册一个转换函数说明数据关系和类型.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| import graphene
from 模型文件 import 模型
class CustomScalar(graphene.Scalar):
''' 自定义标量 '''
@classmethod
def serialize(cls, value):
''' 序列化, 转换过程, 最终需要一个可识别的标量对象 '''
import json
result = json.loads(value.value) # 转换
return result
@convert_django_field.register(模型.无法识别的字段)
def convert_custom(field, registry=None):
return graphene.Field(CustomScalar, description=field.help_text, required=not field.null)
|
django-taggit
该模块的实现的是特殊的外键 TaggableManager , 也会导致的字段的类型未被识别而引发的错误 Exception: Don’t know how to convert the Django field…
这是我的模型:
1
2
3
4
5
6
7
8
9
| from django.db import models
from taggit.managers import TaggableManager
class TestModel1(models.Model):
""" 测试表 """
name = models.CharField(max_length=255, help_text="名称")
tags = TaggableManager()
|
首先我们知道 DjangoObjectType
是模型的基本节点, DjangoListField
是模型列表的基本节点, 而 TestModel1.tags 与 DjangoListField 的 API 一致, 根据 graphene_django 提供的转换注册方法, 直接对应好关系即可.
1
2
3
4
5
6
7
8
9
10
11
12
13
| from taggit.managers import TaggableManager
from taggit.models import Tag
from graphene_django.converter import convert_django_field
# 给 taggit.Tag 模型添加一个 DjangoObjectType
class TaggitType(graphene_django.DjangoObjectType):
class Meta:
model = taggit.models.Tag
@convert_django_field.register(TaggableManager) # 指定模型中未识别的对象
def convert_taggit(field, registry=None):
# 多对多的关系, 注册为 DjangoListField 字段, 类型指定为 TaggitType
return graphene_django.DjangoListField(TaggitType, description=field.help_text, required=not field.null)
|
注意
驼峰转换
auto_camelcase
(True): 表示是否开启驼峰转换, 不开启需设置为 False
1
2
3
4
5
6
7
8
| # schemas.py
import graphene
class Query(graphene.ObjectType):
hello = graphene.String(default_value="Hi!")
schema = graphene.Schema(query=Query, auto_camelcase=False) # 在生成 Schema 的时候设置
|