带有子对象的石墨烯Django变异返回对象失败

时间:2019-08-19 18:32:19

标签: django graphene-python graphene-django

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

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

问题出在executor.py complete_list_value中,该脚本检查footSet是否可迭代。实际上,它是一个RelatedManager,它本身不能迭代。通常,您只需执行table.foot_set.all()即可获得迭代。我发现确实可以在“查询”中正常运行,但不能在“突变”中运行。

我创建了a sample project来说明这一点。

我有一个非常简单的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

schema.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()

如何将我的模型及其潜在的子对象退还给石墨烯,以便根据突变的要求进行处理?我做错了吗?有人有这样的例子可行吗?

0 个答案:

没有答案