如何在Django+GraphQL中正确处理多对多关系?
问题描述
我有一个与User模型存在多对多关系的Game模型,代码如下:
class Game(models.Model): name = models.CharField(max_length=256, blank=True) users = models.ManyToManyField(to=User, blank=True, related_name='games') class User(AbstractUser): email = models.EmailField(max_length=128, verbose_name='email address', blank=False)
我需要将其与GraphQL关联,实现通过mutations读取和修改users字段。现有的Game查询schema不含users字段时可以正常工作:
{ games { edges { node { id name } } } }
但添加users字段后无法正常工作,原因是数据库中Game表没有users字段,多对多关系由games_game_users中间表维护。请问该如何修改代码实现game.users字段的交互?
解决方案
假设使用graphene-django实现Django与GraphQL的集成,按以下步骤修改:
1. 定义GraphQL类型,支持查询users字段
在Game的GraphQL类型中显式添加users字段,关联已定义的User类型:
import graphene from graphene_django import DjangoObjectType from .models import Game, User class UserType(DjangoObjectType): class Meta: model = User fields = ("id", "username", "email") # 根据需求选择返回字段 class GameType(DjangoObjectType): class Meta: model = Game fields = ("id", "name", "users") # 加入users字段 class Query(graphene.ObjectType): games = graphene.List(GameType) def resolve_games(root, info, **kwargs): return Game.objects.all()
修改后,查询schema即可正常请求users字段:
{ games { edges { node { id name users { id username email } } } } }
2. 实现Mutation,支持添加/移除用户与游戏的关联
添加用户到游戏
class AddUserToGame(graphene.Mutation): class Arguments: game_id = graphene.ID(required=True) user_id = graphene.ID(required=True) game = graphene.Field(GameType) def mutate(root, info, game_id, user_id): game = Game.objects.get(pk=game_id) user = User.objects.get(pk=user_id) game.users.add(user) return AddUserToGame(game=game)
从游戏移除用户
class RemoveUserFromGame(graphene.Mutation): class Arguments: game_id = graphene.ID(required=True) user_id = graphene.ID(required=True) game = graphene.Field(GameType) def mutate(root, info, game_id, user_id): game = Game.objects.get(pk=game_id) user = User.objects.get(pk=user_id) game.users.remove(user) return RemoveUserFromGame(game=game)
注册Mutation
class Mutation(graphene.ObjectType): add_user_to_game = AddUserToGame.Field() remove_user_from_game = RemoveUserFromGame.Field() schema = graphene.Schema(query=Query, mutation=Mutation)
Mutation调用示例
添加用户到游戏:
mutation { addUserToGame(gameId: "1", userId: "2") { game { id name users { id username } } } }
从游戏移除用户:
mutation { removeUserFromGame(gameId: "1", userId: "2") { game { id name users { id username } } } }
核心说明
- Django多对多字段无需直接操作中间表,通过模型的
add()/remove()方法即可维护关联,graphene-django会自动处理中间表的数据库操作。 - 只要在GraphQL类型中正确关联模型的多对多字段,框架就会自动解析并返回关联数据。
内容的提问来源于stack exchange,提问作者Narek
相关产品推荐
相关产品推荐

