Как сделать мутации "многие-ко-многим" в Django-Graphene?

Я работаю в Django 3.2 и graphene-django 2.15. Кстати, я все еще учусь использовать Graphene.

Примечание: Мне не разрешено делиться всем кодом, поэтому я переписал его для целей этого вопроса. Пожалуйста, сообщите мне, если вы нашли какую-либо ошибку, не связанную с вопросом.

У меня есть модель Team, которая имеет отношения "многие-ко-многим" с моделью Django Group по умолчанию:

from django.db import models
from django.contrib.auth.models import Group

class Team(models.Model):
    team_id = models.IntegerField(unique=True)  # Custom ID not related to Django's pk
    name = models.CharField(max_length=255)
    groups = models.ManyToManyField(Group, blank=True)

Вот моя схема:

import graphene
from django.contrib.auth.models import Group
from graphene_django import DjangoObjectType

from .models import Team


class TeamType(DjangoObjectType):
    class Meta:
        model = Team

class GroupType(DjangoObjectType):
    class Meta:
        model = Group


class GroupInput(graphene.InputObjectType):
    id = graphene.ID(required=True)


class UpdateTeam(graphene.Mutation):
    team = graphene.Field(TeamType)

    class Arguments:
        team_id = graphene.ID(required=True)
        name = graphene.String(required=True)
        groups_id = graphene.List(GroupInput, required=True)

    def mutate(self, info, team_id, name, groups_id):
        team = Team.objects.get(pk=team_id)

        team.name = name
        team.groups = Group.objects.filter(pk__in=groups_id)

        team.save()
        return UpdateTeam(team=team)

        
class TeamMutations(graphene.ObjectType):
    update_team = UpdateTeam.Field()

class Mutation(TeamMutations, graphene.ObjectType):
    pass

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

Когда я выполняю этот запрос:

mutation{
  updateTeam(
    teamId: 65961826547,
    name: "My Team Name",
    groupsId: [{id: 1}, {id: 2}]
  ) {
    team {
      team_id,
      name,
      groups {
        name,
      }
    }
  }
}

Я получаю эту ошибку:

{
  "errors": [
    {
      "message": "Field 'id' expected a number but got {'id': '1'}.",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "updateTeam"
      ]
    }
  ],
  "data": {
    "updateTeam": null
  }
}

Я не очень понимаю, как отношения "многие к многим" управляются в Graphene. Есть ли у кого-нибудь решение или объяснения для меня? Большое спасибо.

Я нашел решение.

Сначала я подумал, что есть что-то связанное с графеном, особенно эти InputObjectTypes, я не понял правильно.

Но на самом деле проблема очень проста.

GroupInput ожидает одно значение, которым является ID.

class GroupInput(graphene.InputObjectType):
    id = graphene.ID(required=True)

Поскольку я поместил его в graphene.List(), теперь я ожидаю список идентификаторов:

class UpdateTeam(graphene.Mutation):
    ...

    class Arguments:
        ...
        groups_id = graphene.List(GroupInput, required=True)

Но в моем вызове API, вместо того, чтобы дать фактический список, я дал дикту:

mutation{
  updateTeam(
    ...
    groupsId: [{id: 1}, {id: 2}]
  ) {
    ...
  }

Так это работает:

mutation{
  updateTeam(
    ...
    groupsId: [1, 2]
  ) {
    ...
  }

Примечание 1:

graphene.ID также принимает идентификаторы, заданные в виде строк:

    groupsId: ["1", "2"]

Примечание 2:

Я действительно удалил GroupInput и поместил поле graphene.ID непосредственно в graphene.List:

class UpdateTeam(graphene.Mutation):
    ...

    class Arguments:
        ...
        groups_id = graphene.List(graphene.ID, required=True)
Вернуться на верх