首页 > 解决方案 > 带有子对象的石墨烯 Django 突变返回对象失败

问题描述

当我执行一个突变(使用 SerializerMutation)并返回创建的对象时,响应包含一个 AssertionError 声明

User Error: expected iterable, but did not find one for field CreateTableMutationPayload.footSet

问题出在 executor.pycomplete_list_value中,它检查 footSet 是否是可迭代的。它实际上是一个 RelatedManager,它是不可迭代的。通常,您只需执行 table.foot_set.all() 即可获得可迭代对象。我发现它在查询中运行良好但在突变中运行良好,这很奇怪。

我创建了一个示例项目来说明这一点。

我有一个非常简单的模型,Table有几个Foot. 两个对象都通过 Relay 暴露出来,效果很好。查询:

{ tables {
    edges {
      node {
        id, name, height
        footSet {
          edges {
            node {
              id, number, style
} } } } } } } }

返回:

{
    "data": {
        "tables": {
            "edges": [
                {
                    "node": {
                        "id": "VGFibGVOb2RlOjE=",
                        "name": "test1",
                        "height": 11,
                        "footSet": {
                            "edges": [
                                {
                                    "node": {
                                        "id": "Rm9vdE5vZGU6MQ==",
                                        "number": 1,
                                        "style": "plain"
                                    }
                                },
                                {
                                    "node": {
                                        "id": "Rm9vdE5vZGU6Mg==",
                                        "number": 2,
                                        "style": "Almost plain"
} } ] } } } ] } } }

但是一个突变:

mutation {
  createTable(input: {
    name:"test3"
    height: 60
    footSet: [
      { number: 1, style: "Rococo" }
    ]
  }) {
      name
      height
      footSet {
            id
            number
            style
      }
  }
}

产量:

{
  "errors": [
    {
      "message": "User Error: expected iterable, but did not find one for field CreateTableMutationPayload.footSet. (furniture.Foot.None)"
    }
  ],
  "data": {
    "createTable": {
      "name": "test3",
      "height": 60,
      "footSet": null
    }
  }
}

要使用示例,您只需要

source bin/activate
pip -r requirements.txt
./manage.py migrate
./manage.py createsuperuser
./manage.py runserver :7000
Connect to localhost:7000/admin
Go to localhost:7000/graphql

架构.py:

import json

import graphene
from graphene import Schema
from graphene_django import DjangoObjectType
from graphene_django.filter import DjangoFilterConnectionField

from furniture.models import Table, Foot
from graphene_django.rest_framework.mutation import SerializerMutation

from furniture.serializers import TableSerializer


class TableNode(DjangoObjectType):
    class Meta:
        model = Table
        filter_fields = "__all__"
        interfaces = (graphene.relay.Node,)


class FootNode(DjangoObjectType):
    class Meta:
        model = Foot
        filter_fields = "__all__"
        interfaces = (graphene.relay.Node,)


class Query(graphene.ObjectType):
    tables = DjangoFilterConnectionField(TableNode)


class CreateTableMutation(SerializerMutation):
    class Meta:
        serializer_class = TableSerializer
        model_operations = ['create', 'update']
        lookup_field = 'id'


class Mutation(graphene.ObjectType):
    create_table = CreateTableMutation.Field()


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

和serializers.py:

from rest_framework import serializers

from .models import Table, Foot


class FootSerializer(serializers.Serializer):
    class Meta:
        model = Foot

    number = serializers.IntegerField()
    style = serializers.CharField()

    def update(self, instance, validated_data):
        pass

    def create(self, validated_data):
        pass

    def get_attribute(self, instance):
        print("get_attr", self, instance)
        return []


class TableSerializer(serializers.Serializer):
    class Meta:
        model = Table

    name = serializers.CharField()
    height = serializers.IntegerField()
    foot_set = FootSerializer(many=True, required=False)

    def update(self, instance, validated_data):
        pass

    def create(self, validated_data):
        feet = validated_data.pop('foot_set') if 'foot_set' in validated_data else []
        print("feet", type(feet), str(feet))
        table = Table.objects.create(name=validated_data['name'], height=validated_data['height'])
        for foot in feet:
            Foot.objects.create(table=table, number=foot['number'], style=foot['style'])

        table.refresh_from_db()
        print("created table", table)
        return table
        # also tried Table.objects.filter(id=table.id).prefetch_related("foot_set").first()

如何根据突变的要求返回我的模型及其潜在的子对象以供石墨烯处理?我做错了吗?有人有这样一个有效的例子吗?

标签: djangographene-pythongraphene-django

解决方案


推荐阅读