Мутация GraphQL в графене для объекта с отношением внешнего ключа - PullRequest
1 голос
/ 22 марта 2020

Я создаю простой интерфейс CRUD с Python, GraphQL (графен- django) и Django. Мутация CREATE для объекта (Ingredient), которая включает отношения внешнего ключа к другому объекту (Category), не будет работать. Я хочу дать GraphQL идентификатор CategoryObject, а не целый экземпляр категории. Затем в бэкэнде он должен нарисовать отношение к объекту Category.

В модели Django объект Ingredient содержит экземпляр объекта Category внешнего ключа (см. Код ниже). Целый ли объект категории необходим здесь, чтобы нарисовать отношение и использовать Ingredient.objects.select_related('category').all()?

Мутация create ожидает IngredientInput, которая включает все свойства и целочисленное поле для отношения внешнего ключа. Таким образом, сама мутация graphQL в настоящее время работает так, как я хочу.

Мой вопрос похож, если не совпадает с этот , но эти ответы мне не помогают.

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

{
  "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 Ответ

1 голос
/ 26 марта 2020

У меня была такая же проблема сегодня.

Ошибка Cannot assign \"8\": \"Ingredient.category\" must be a \"Category\" instance. - это ошибка Django, которая возникает, когда вы пытаетесь создать объект, используя целое число внешнего ключа непосредственно вместо объекта. Если вы хотите использовать идентификатор внешнего ключа напрямую, вы должны использовать суффикс _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. Если вы хотите sh сохранить имя category, вы должны изменить его на:

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

Cheers!

...