使用 Django 与 Graphene 构建 GraphQL API:学校管理系统的模型、查询与 Resolver 实战
【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine
本指南以"学校管理系统"为场景,基于 Python + Django + Graphene-Django 从零搭建一个具有学生、教师、课程三层数据关系的 GraphQL API,完整覆盖虚拟环境搭建、ORM 模型与关系设计、DjangoObjectType类型映射、Query/Resolver 实现、GraphiQL 测试等全流程,并延伸讲解当前仓库中 @refinedev/graphql 数据提供器如何消费这类 GraphQL 后端,帮助读者同时掌握"后端如何提供 GraphQL"与"前端如何接入 GraphQL"的完整链路。
为什么选择 GraphQL 承载复杂业务 API
GraphQL 是一种面向数据库通信的查询语言,它的最大价值体现在数据结构复杂、前端只需要请求自己所需字段的场景。与 REST 固定的资源端点不同,GraphQL 采用强类型 Schema 与固定数据结构:
- 声明式模型让 API 一致且可预测:当后端字段变化时,前端可以借助 Schema 契约提前感知,避免在每次后端变更时同步修改前端代码;
- 按需取数、降低网络开销:客户端只取自己需要的字段,减少冗余数据传输,从整体上提升系统性能;
- 聚合多服务数据:在微服务架构中,前端只需调用一个 GraphQL 端点,后端即可在处理、合并、过滤后把来自不同服务的数据一次性返回,从而大幅削减请求次数。
本文将要实现的具体场景是:学校管理系统中有已注册的学生(Student)、教师(Teacher)与课程(Course),课程与教师为一对多关系,课程与学生为多对多关系;我们要通过 GraphQL 一次查询出"课程 + 该课程授课教师 + 该课程全部选课学生"这样的嵌套数据。
前置条件与技术选型
构建 GraphQL API 可以基于多种后端技术栈,最常见的是 Node.js、Python(Flask)与 Python(Django)。本文采用:
| 组件 | 说明 |
|---|---|
| Python | 按操作系统从官网下载安装,本文环境为 Windows OS + VS Code + 命令行终端,Python 版本3.12.3 |
| Django | 作为 Web 框架,提供清晰、务实的工程结构以加速开发,且自带开发用 Web 服务器,无需额外配置 |
| Graphene-Django | 专门用于在 Django 框架中集成 GraphQL 的官方库 |
Django 内置了开发服务器,因此不需要像传统方案那样单独搭建 Web 服务器,这让环境准备和联调都更加轻量。
搭建 Django + Graphene 开发环境
创建并激活虚拟环境
在项目目录中打开命令行终端,执行以下命令创建并激活虚拟环境(Windows 环境示例):
python -m venv smsvenv .\smsvenv\Scripts\activate虚拟环境用于隔离项目依赖,激活后需要在其内部安装 Django 与 Graphene-Django:
pip install django pip install graphene-django初始化项目与应用
使用 Django 命令行工具创建项目骨架并新建应用:
django-admin startproject school_management cd school_management django-admin startapp school说明:原教程中
django-admin startapp需指定应用名,即django-admin startapp school,这样才能生成名为school的应用目录,用于放置models.py、views.py、schema.py等文件。
注册应用到 INSTALLED_APPS
打开school_management/settings.py,把graphene_django和school两个应用加入INSTALLED_APPS:
INSTALLED_APPS = [ # Django 内置应用 "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", # 第三方与业务应用 "graphene_django", "school", ]至此开发环境搭建完毕,可以开始设计数据模型与 GraphQL API。
数据库设置与模型关系设计
使用 Django 默认的 SQLite 配置
在school_management/settings.py的DATABASES配置中,Django 默认提供 SQLite 配置,无需任何额外数据库服务即可运行,适合本教程的开发与学习场景:
DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": BASE_DIR / "db.sqlite3", } }定义 Student、Teacher、Course 三个模型
在school/models.py中使用 Django ORM 定义三个模型类,各自包含对应的字段与类型:
from django.db import models class Student(models.Model): name = models.CharField(max_length=100) age = models.IntegerField() class Teacher(models.Model): name = models.CharField(max_length=100) class Course(models.Model): name = models.CharField(max_length=100)描述模型关系:多对多与一对多
多对多(ManyToMany):每个学生可以选修多门课程,每门课程也可以有多个学生。在Course模型下声明students字段:
class Course(models.Model): name = models.CharField(max_length=100) students = models.ManyToManyField(Student)一对多(One-to-Many):每门课程只有一位授课教师,但一位教师可以教授多门课程。在Course模型下创建指向Teacher的外键字段:
class Course(models.Model): name = models.CharField(max_length=100) teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE) students = models.ManyToManyField(Student)最终的整体关系为:Course通过外键关联单个Teacher,通过多对多关联多个Student,Teacher与Student之间不直接关联——这正好对应"查询课程时同时取回教师与选课学生"的嵌套数据需求。
插入示例数据:从迁移到 Django Admin
有多种方式向表中插入示例数据,本文使用 Django Admin 管理界面:
1. 生成并执行数据库迁移:
python manage.py makemigrations python manage.py migrate2. 创建超级用户:
python manage.py createsuperuser3. 在school/admin.py中注册模型:
from django.contrib import admin from .models import Student, Teacher, Course admin.site.register(Student) admin.site.register(Teacher) admin.site.register(Course)4. 启动开发服务器:
python manage.py runserver5. 浏览器访问管理后台:
http://localhost:8000/admin
6. 使用超级用户登录后,在管理界面分别添加教师、学生与课程数据,并为课程指定授课教师、勾选选课学生。有了这些示例数据,后续的 GraphQL 查询才能返回有意义的嵌套结果。
用 Graphene-Django 实现 GraphQL Schema
Schema 文件的两大组成部分
在school/目录下新建schema.py文件,它包含两个主要部分:
- Types(类型):定义客户端请求的数据结构;
- Queries + Resolvers(查询与解析器):定义从数据库读取数据(只读操作)的查询。
使用 DjangoObjectType 定义 GraphQL 类型
DjangoObjectType是 Graphene-Django 的核心能力:只需声明Meta.model,它就会依据 Django 模型的字段自动生成对应的 GraphQL 字段,免去手写每个字段的重复工作:
# schema.py import graphene from graphene_django.types import DjangoObjectType from .models import Student, Teacher, Course class StudentType(DjangoObjectType): class Meta: model = Student class TeacherType(DjangoObjectType): class Meta: model = Teacher class CourseType(DjangoObjectType): class Meta: model = CourseCourseType会自动暴露外键teacher与多对多students字段,这正是实现嵌套查询的基础。
定义 Query 与 Resolver 获取嵌套数据
现在用类型去数据库中取数。例如,我们需要获取"教师所授课程及其全部选课学生"的信息,就需要定义一个包含各类型 GraphQL 列表的Query,并为每个列表字段实现对应的 Resolver:
# schema.py import graphene from graphene_django.types import DjangoObjectType from .models import Student, Teacher, Course class StudentType(DjangoObjectType): class Meta: model = Student class TeacherType(DjangoObjectType): class Meta: model = Teacher class CourseType(DjangoObjectType): class Meta: model = Course class Query(graphene.ObjectType): all_students = graphene.List(StudentType) all_teachers = graphene.List(TeacherType) all_courses = graphene.List(CourseType) def resolve_all_students(self, info): return Student.objects.all() def resolve_all_teachers(self, info): return Teacher.objects.all() def resolve_all_courses(self, info): return Course.objects.all() schema = graphene.Schema(query=Query)注意:Query 仅用于只读操作(如排序、过滤);需要更新数据时必须使用 Mutations(变更操作),这是 GraphQL 对读写职责的明确划分。
创建 GraphQL 视图并注册路由
最后把 GraphQL 接入 Django:在school/views.py中添加视图,将 Schema 与GraphQLView绑定;再在school_management/urls.py中把 URL 映射到该视图,即可通过浏览器访问:
# school/views.py from django.http import JsonResponse from graphene_django.views import GraphQLView from .schema import schema def graphql_view(request): view = GraphQLView.as_view(schema=schema, graphiql=True) return view(request)# school_management/urls.py from django.contrib import admin from school.views import graphql_view from django.urls import path urlpatterns = [ path("admin/", admin.site.urls), path("graphql/", graphql_view), ]使用 GraphiQL 测试 API
在上面的graphql_view中传入graphiql=True,Django 就会为/graphql/端点启用 GraphiQL 交互式界面。启动服务器后访问:
http://127.0.0.1:8000/graphql/
在 GraphiQL 左侧输入查询语句,右侧即可看到响应。例如下面的查询会一次性取回每门课程的名称、授课教师姓名,以及所有选课学生的姓名与年龄:
query { allCourses { name teacher { name } students { name age } } }响应示例:
{ "data": { "allCourses": [ { "name": "Algebra", "teacher": { "name": "Ms. Smith" }, "students": [ { "name": "Alice", "age": 15 }, { "name": "Bob", "age": 16 } ] } ] } }GraphiQL 还自带文档面板与自动补全,可以直接观察Query、StudentType、TeacherType、CourseType暴露的全部字段,非常便于验证 Schema 设计与实际返回结构。除了 GraphiQL,也可以使用 Postman 等工具以 HTTP POST 方式发送 GraphQL 查询。
前端如何消费这类 GraphQL API:refine 的 @refinedev/graphql
完成后端 GraphQL API 之后,前端接入是另一大关键环节。当前仓库中的 packages/graphql 包(@refinedev/graphql,见 package.json)为 Refine 提供了 GraphQL 数据提供器与实时提供器,让 React 应用可以直接消费上文这类 Django/Graphene 后端。
用 urql Client 创建数据提供器
数据提供器的工厂函数位于 dataProvider/index.ts。其创建方式以 urqlClient为核心参数(示例参见 examples/data-provider-graphql/src/App.tsx):
import { Client, fetchExchange } from "@urql/core"; import createDataProvider, { createLiveProvider } from "@refinedev/graphql"; import { createClient } from "graphql-ws"; const API_URL = "https://api.nestjs-query.refine.dev/graphql"; const WS_URL = "wss://api.nestjs-query.refine.dev/graphql"; export const client = new Client({ url: API_URL, exchanges: [fetchExchange], }); // 在 Refine 中注册 <Refine dataProvider={createDataProvider(client)} liveProvider={createLiveProvider(createClient({ url: WS_URL }))} ... />按操作定制的 dataMapper 与 buildVariables
dataProvider/options.ts 中定义了GraphQLDataProviderOptions,允许为create、createMany、getOne、getList、getMany、update、updateMany、deleteOne、deleteMany、custom每个操作单独定制两件事:
buildVariables:把 Refine 的查询参数(如id、variables、pagination、sorters、filters、meta.gqlVariables)转换成 GraphQL 操作变量。例如getOne.buildVariables返回{ id: params.id, ...params.meta?.gqlVariables },update.buildVariables返回{ input: { id, update: params.variables } };dataMapper:从响应中提取目标数据,并依赖camelcase与pluralize按资源名推断响应键(如updateOnePost、all_风格命名)。
这与你用 Graphene 后端时的操作命名约定密切相关:GraphQL 操作的名称(如allCourses、updateOneCourse)与资源命名方式,需要与dataMapper默认推断规则或自定义meta保持一致,前后端才能正确对接。
内置的分页、排序与过滤
在 utils/getListHelpers.ts 中实现了将 Refine 通用参数翻译为 GraphQL 变量的逻辑:
buildPagination:把{ pageSize, currentPage }转为{ limit, offset },分页关闭时返回{ limit: 2147483647 };buildSorters:把排序字段与方向转为{ field, direction };buildFilters:维护了一张运算符映射表,例如eq → eq、ne → neq、nin → notIn、contains → iLike、between → between等,并支持and/or组合过滤。
用 liveProvider 订阅数据变更
liveProvider/index.ts 中的createLiveProvider基于graphql-ws提供实时能力:useList场景会同时订阅created、updated、deleted三类事件,useOne场景订阅updated事件。这与 GraphQL 后端的 Subscriptions 能力相对应——如果你的 Django 后端需要实时推送,可以参考同样的订阅模式进行扩展。
总结
本文以学校管理系统为完整案例,走通了从 GraphQL 概念、Python/Django 环境搭建、ORM 模型与关系建模、示例数据录入,到 Graphene-Django 的DjangoObjectType类型定义、Query/Resolver 实现、视图与路由注册,以及 GraphiQL 实测的端到端流程。GraphQL 最适合在"API 需要被不同客户端以特定数据结构集成"或"客户端只需要少量特定字段、追求高性能与低带宽占用"的场景中发挥价值;理解 Schema、Type、Query 与 Mutation 的分工后,再配合 Refine 生态的 @refinedev/graphql 数据提供器,就能把 Django + Graphene 构建的后端能力无缝接入 React 前端应用,形成一套完整、可复用的全栈 CRUD 与实时数据方案。
【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考