GraphQL在Django中的使用

简介

特点

  • 请求你所要的数据,不多不少
  • 获取多个资源,只用一个请求
  • 描述所有的可能,类型系统
  • 几乎所有语言支持

谁在用

GraphQL在Django中的使用_第1张图片

文档

  • Graphene-Python
  • GraphQL | A query language for your API
    GraphQL在Django中的使用_第2张图片

背景

  • 传统restful的接口定义类型多,试图简化接口定义
  • django中使用restframework定义restful资源接口时,可能会出现深度查询,造成有时候查询过度
  • 例如前端用户需要查询接口用于展示在下拉框时,用户仅需要id与value值时,造成无用字段冗余,影响接口返回性能
  • 当一张表字段较多时,例如接口1一共有40个字段,A页面需要5个字段做展示,B页面需要另外10个字段展示,这时我们需要根据用户需求定义返回接口提升性能,且数据不会被暴露

实际问题

GraphQL在Django中的使用_第3张图片

GraphQL在Django中的使用_第4张图片

问题

  • 请求数据量40kB可以根据用户缩减,也就是返回数据量可以做到<40KB
  • 后端数据实际耗时783ms,但是数据传输一共耗时5s
    Django中如何使用呢
    安装
pip install graphene-django

django配置

INSTALLED_APPS = [
    "django.contrib.staticfiles", 
    "graphene_django"
    ]
GRAPHENE = {
    "SCHEMA": "test_api.schema.schema" # 下文中需要定义schema.py文件
}

Demo

定义数据库模型

from django.db import models


class Category(models.Model):
    name = models.CharField(max_length=100, help_text="名称")
    id = models.BigAutoField(primary_key=True)


class Ingredient(models.Model):
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=100, help_text="名称")
    notes = models.TextField(help_text="笔记")
    category = models.ForeignKey(
        Category, related_name="category", on_delete=models.CASCADE
    )

    def __str__(self):
        return self.name

定义serializer

from graphene_django.rest_framework.mutation import SerializerMutation
from rest_framework.serializers import ModelSerializer

from ..models import Category, Ingredient


class CategorySerializer(ModelSerializer):
    class Meta:
        model = Category
        fields = "__all__"


class IngredientSerializer(ModelSerializer):
    class Meta:
        model = Ingredient
        fields = "__all__"

定义接口

import graphene
from graphene import relay
from graphene_django import DjangoObjectType
from graphene_django.filter import DjangoFilterConnectionField
from graphene_django.rest_framework.mutation import SerializerMutation

from ..models import Category, Ingredient

from ..serializer import CategorySerializer, IngredientSerializer


# 为查询添加查询总数
class CountableConnectionBase(relay.Connection):
    class Meta:
        abstract = True

    total_count = graphene.Int()

    def resolve_total_count(self, info, **kwargs):
        return self.iterable.count()


# Ingredient 查看过滤
class IngredientFilter(DjangoObjectType):
    class Meta:
        model = Ingredient
        fields = "__all__"
        filter_fields = {
            "name": ['exact', "contains", "istartswith"],
            "category": ["exact"],
            'category__name': ['exact'],
        }
        interfaces = (relay.Node,)
        connection_class = CountableConnectionBase

    extra_field = graphene.String()

    def resolve_extra_field(self: Ingredient, info):
        return "hello!" + str(self.id)


# CategoryFilter 查询过滤
class CategoryFilter(DjangoObjectType):
    class Meta:
        model = Category
        fields = "__all__"
        filter_fields = {
            "name": ['exact', "contains", "istartswith"],
        }
        interfaces = (relay.Node,)
        connection_class = CountableConnectionBase


# CategoryMutation 修改或新增
class CategoryMutation(SerializerMutation):
    class Meta:
        serializer_class = CategorySerializer


# IngredientMutation 修改或新增
class IngredientMutation(SerializerMutation):
    class Meta:
        serializer_class = IngredientSerializer


# 汇总query接口
class ApiQuery(graphene.ObjectType):
    search_category = DjangoFilterConnectionField(CategoryFilter)
    search_ingredient = DjangoFilterConnectionField(IngredientFilter)


# 汇总操作类接口
class ApiMutation(graphene.ObjectType):
    update_category = CategoryMutation.Field()
    update_ingredient = IngredientMutation.Field()

汇总所有接口

import graphene

from .api import ApiQuery, ApiMutation


class Query(ApiQuery):
    # 新增时提供多继承即可
    pass


class Mutation(ApiMutation):
    # 新增时提供多继承即可
    pass


schema = graphene.Schema(query=Query, mutation=Mutation)

启动

python manage.py runserver 0.0.0.0:8080
  • 接口文档
    GraphQL在Django中的使用_第5张图片
    GraphQL在Django中的使用_第6张图片

总结

  • 查询时,可以使用django_filter , 快速查询
  • 用法基本和drf框架基本类似
  • 接口面涉及的深度查询,通过connection实现,如果返回字段中没有改要求,将不会深度查询

你可能感兴趣的:(python,django,graphql,python)