You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 11:57:40