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

Posted

技术标签:

【中文标题】具有外键关系的对象的石墨烯中的 GraphQL 突变【英文标题】:GraphQL Mutation in Graphene for Object with Foreign Key Relation 【发布时间】:2020-07-03 05:24:59 【问题描述】:

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

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

创建突变需要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
      categoryname
    

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】:

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

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")

干杯!

【讨论】:

感谢您提供非常有用且详细的回答! 这正是我想要的!我希望这是最好的做法!

以上是关于具有外键关系的对象的石墨烯中的 GraphQL 突变的主要内容,如果未能解决你的问题,请参考以下文章

如何在石墨烯中返回字典列表?

Python GraphQL 如何声明一个自引用的石墨烯对象类型

在石墨烯中使用与多个解析器相同的连接

如何在 python 石墨烯中处理带参数的查询

如何解决具有多对多关系的石墨烯 django 节点字段

GraphQL 突变为嵌套响应返回 null