具有外键关系的对象的石墨烯中的GraphQL突变

时间:2020-03-22 16:26:21

标签: python django graphql graphene-django

我正在使用Python,GraphQL(graphene-django)和Django构建一个简单的CRUD接口。包含与另一个对象(Ingredient)的外键关系的对象(Category)的CREATE突变将不起作用。我想给GraphQL CategoryObject而不是整个类别实例的ID。然后在后端中应绘制与Category对象的关系。

在Django模型中,成分对象包含外键类别对象的实例(请参见下面的代码)。这里是否需要整个类别对象来绘制关系并使用Ingredient.objects.select_related('category').all()

create突变期望IngredientInput包括所有属性和外键关系的整数字段。因此,graphQL突变本身目前可以按我的意愿工作。

我的问题与this one相似,但不相同,但是这些答案对我没有帮助。

models.py:

class Category(models.Model):
    name = models.CharField(max_length=50, unique=True)
    notes = models.TextField()

    class Meta:
        verbose_name = u"Category"
        verbose_name_plural = u"Categories"
        ordering = ("id",)

    def __str__(self):
        return self.name


class Ingredient(models.Model):
    name = models.CharField(max_length=100)
    notes = models.TextField()
    category = models.ForeignKey(Category, on_delete=models.CASCADE)

    class Meta:
        verbose_name = u"Ingredient"
        verbose_name_plural = u"Ingredients"
        ordering = ("id",)

    def __str__(self):
        return self.name

schema.py:

class CategoryType(DjangoObjectType):
    class Meta:
        model = Category


class CategoryInput(graphene.InputObjectType):
    name = graphene.String(required=True)
    notes = graphene.String()


class IngredientType(DjangoObjectType):
    class Meta:
        model = Ingredient


class IngredientInput(graphene.InputObjectType):
    name = graphene.String(required=True)
    notes = graphene.String()
    category = graphene.Int()


class CreateIngredient(graphene.Mutation):
    class Arguments:
        ingredientData = IngredientInput(required=True)

    ingredient = graphene.Field(IngredientType)

    @staticmethod
    def mutate(root, info, ingredientData):
        _ingredient = Ingredient.objects.create(**ingredientData)
        return CreateIngredient(ingredient=_ingredient)


class Mutation(graphene.ObjectType):
    create_category = CreateCategory.Field()
    create_ingredient = CreateIngredient.Field()

graphql_query:

mutation createIngredient($ingredientData: IngredientInput!) {
  createIngredient(ingredientData: $ingredientData) {
    ingredient {
      id
      name
      notes
      category{name}
    }

graphql变量:

{
  "ingredientData": {
    "name": "milk",
    "notes": "from cow",
    "category": 8  # here I ant to insert the id of an existing category object
  }
}
执行查询后

错误消息:

{
  "errors": [
    {
      "message": "Cannot assign \"8\": \"Ingredient.category\" must be a \"Category\" instance.",
      "locations": [
        {
          "line": 38,
          "column": 3
        }
      ],
      "path": [
        "createIngredient"
      ]
    }
  ],
  "data": {
    "createIngredient": null
  }
}

1 个答案:

答案 0 :(得分:3)

我今天也遇到同样的问题。

Cannot assign \"8\": \"Ingredient.category\" must be a \"Category\" instance.错误是Django错误,当您尝试直接使用外键整数而不是对象来创建对象时发生。 如果要直接使用外键ID,则必须使用_id后缀。

例如,代替使用:

_ingredient = Ingredient.objects.create(name="milk", notes="from_cow", category=8)

您必须使用其中一个

category_obj = Category.objects.get(id=8)
_ingredient = Ingredient.objects.create(name="milk", notes="from_cow", category=category_obj)

_ingredient = Ingredient.objects.create(name="milk", notes="from_cow", category_id=8)

如果使用GraphQL,则必须将InputObjectType字段设置为 _id。就您而言:

class IngredientInput(graphene.InputObjectType):
    name = graphene.String(required=True)
    notes = graphene.String()
    category_id = graphene.Int()

但是,这会使您在架构中的字段显示为categoryId。如果您希望保留category名称,则必须更改为:

category_id = graphene.Int(name="category")

干杯!