JavaRush /Курсы /Модуль 3: Django /Написание запросов (queries) и мутаций (mutations)

Написание запросов (queries) и мутаций (mutations)

Модуль 3: Django
24 уровень , 4 лекция
Открыта

Продолжаем изучать GraphQL. Сегодня мы разберем, как создавать запросы (queries) для получения данных

и мутации (mutations) для изменения данных. Приступаем!

Основы работы с Query в GraphQL

Query — это способ запрашивать данные от API. Главная особенность GraphQL в том, что клиент сам определяет структуру ответа. Это немного похоже на поход в ресторан, где вы не заказываете "суп", а говорите: "Мне, пожалуйста, суп, но только без морковки и побольше картошки".

Начнем с простого примера запроса, например, списка пользователей. Предположим, у нас уже есть модель пользователя:

# models.py
from django.db import models

class User(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)

Теперь создадим GraphQL-схему для получения данных о пользователях:

# schema.py
import graphene
from graphene_django.types import DjangoObjectType
from .models import User

class UserType(DjangoObjectType):
    class Meta:
        model = User

class Query(graphene.ObjectType):
    all_users = graphene.List(UserType)

    def resolve_all_users(root, info):
        return User.objects.all()

schema = graphene.Schema(query=Query)
  1. DjangoObjectType — это специальный тип, который позволяет автоматически связать нашу модель Django с GraphQL.
  2. all_users — описание запроса: он вернет список всех пользователей.
  3. resolve_all_users — функция, которая выполняет запрос к базе данных и возвращает данные.

Теперь мы можем протестировать это в GraphiQL или другом инструменте:

query {
    allUsers {
        name
        email
    }
}

В ответе мы получим:

{
  "data": {
    "allUsers": [
      {
        "name": "Alice",
        "email": "alice@example.com"
      },
      {
        "name": "Bob",
        "email": "bob@example.com"
      }
    ]
  }
}

Динамические запросы: работа с параметрами

Иногда нам нужны данные не обо всех пользователях, а о конкретном. Добавим возможность искать пользователя по ID:

class Query(graphene.ObjectType):
    user_by_id = graphene.Field(UserType, id=graphene.Int(required=True))

    def resolve_user_by_id(root, info, id):
        return User.objects.get(pk=id)

Теперь запрос может выглядеть так:

query {
    userById(id: 1) {
        name
        email
    }
}

А ответ:

{
  "data": {
    "userById": {
      "name": "Alice",
      "email": "alice@example.com"
    }
  }
}
⚠️ Типичная ошибка:

обращение к несуществующему ID приведет к исключению DoesNotExist. Этот сценарий можно обработать, возвращая None или выбрасывая понятное клиенту исключение.

Основы работы с Mutation в GraphQL

Mutation (мутация) — это способ изменять данные (добавлять, обновлять или удалять). Концептуально это похоже на HTTP POST/PUT/DELETE запросы в REST, но работает гибче и централизованно.

Приведём пример базовой мутации. Добавим возможность создавать пользователя через GraphQL:

class CreateUser(graphene.Mutation):
    class Arguments:
        name = graphene.String(required=True)
        email = graphene.String(required=True)

    user = graphene.Field(UserType)

    def mutate(root, info, name, email):
        user = User(name=name, email=email)
        user.save()
        return CreateUser(user=user)

class Mutation(graphene.ObjectType):
    create_user = CreateUser.Field()

Как это работает:

  1. Arguments — описывает входные параметры для мутации.
  2. mutate — функция, выполняющая логику создания. Она получает параметры, создает объект и возвращает его.
  3. user — результат, который вернется клиенту.

Теперь тестируем мутацию:

mutation {
    createUser(name: "Charlie", email: "charlie@example.com") {
        user {
            name
            email
        }
    }
}

В ответе мы получаем:

{
  "data": {
    "createUser": {
      "user": {
        "name": "Charlie",
        "email": "charlie@example.com"
      }
    }
  }
}

И запись появляется в базе данных. Успех!

Обновление данных с помощью Mutation

Окей, пользователь создал свой аккаунт с опечаткой в имени. Давайте добавим функцию для обновления имени пользователя:

class UpdateUser(graphene.Mutation):
    class Arguments:
        id = graphene.Int(required=True)
        name = graphene.String(required=True)

    user = graphene.Field(UserType)

    def mutate(root, info, id, name):
        user = User.objects.get(pk=id)
        user.name = name
        user.save()
        return UpdateUser(user=user)

class Mutation(graphene.ObjectType):
    update_user = UpdateUser.Field()

Запрос для обновления:

mutation {
    updateUser(id: 1, name: "Alice Updated") {
        user {
            name
        }
    }
}

И в ответе видим:

{
  "data": {
    "updateUser": {
      "user": {
        "name": "Alice Updated"
      }
    }
  }
}
⚠️ Типичная ошибка:

запрос к несуществующему ID также может выбросить исключение, поэтому добавление проверки с сообщением об ошибке — хорошая практика.

Удаление данных с помощью Mutation

Добавим функцию удаления пользователя:

class DeleteUser(graphene.Mutation):
    class Arguments:
        id = graphene.Int(required=True)

    ok = graphene.Boolean()

    def mutate(root, info, id):
        try:
            user = User.objects.get(pk=id)
            user.delete()
            return DeleteUser(ok=True)
        except User.DoesNotExist:
            return DeleteUser(ok=False)

class Mutation(graphene.ObjectType):
    delete_user = DeleteUser.Field()

Теперь запрос для удаления:

mutation {
    deleteUser(id: 1) {
        ok
    }
}

Ответ, если ID существует:

{
  "data": {
    "deleteUser": {
      "ok": true
    }
  }
}

Тестирование запросов и мутаций

Не забывайте тестировать ваши запросы и мутации через GraphiQL или GraphQL Playground. Убедитесь, что запросы ведут себя предсказуемо, а ошибки возвращаются в понятном формате клиенту.

Пример ошибок:

  1. Отсутствие обязательного параметра: GraphQL возвращает ошибку о недостающем аргументе.
  2. Некорректный параметр: стоит убедиться, что введенные значения валидируются, например, email проверяется на корректность.

Оптимизация запросов

Для повышения скорости, особенно при работе с большими объемами данных, используйте Django QuerySet методы select_related и prefetch_related, чтобы минимизировать количество запросов к базе данных.

Пример с select_related:

def resolve_all_users(root, info):
    return User.objects.select_related("profile").all()

GraphQL дает возможность объединить запросы и мутации в единый, мощный инструмент взаимодействия между клиентом и сервером. При правильной настройке вы сможете достичь гибкости и эффективности, о которой REST только мечтает. Вперед к следующей лекции! 😉

1
Задача
Модуль 3: Django, 24 уровень, 4 лекция
Недоступна
Добавление данных через Mutation
Добавление данных через Mutation
1
Задача
Модуль 3: Django, 24 уровень, 4 лекция
Недоступна
Фильтрация и обновление данных
Фильтрация и обновление данных
3
Опрос
Введение в GraphQL с Django, 24 уровень, 4 лекция
Недоступен
Введение в GraphQL с Django
Введение в GraphQL с Django
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Дмитрий/MrJonson Уровень 90
30 ноября 2025
Во второй задаче, в миграциях какой то кло....н оставил не закомментированный код по этому задача не проходит тестирование # ``` ### Пример использования GraphQL: #### Запрос на получение всех книг: # ```graphql # query { # allBooks { # title # author { # name # } # } # } # ``` #### Запрос на получение книг, начинающихся с "T": # ```graphql # query { # booksByTitleStartingWithT { # title # author { # name # } # } # } # ``` #### Мутация для обновления автора: # ```graphql # mutation { # updateBookAuthor(bookId: 1, newAuthorName: "New Author") { # book { # title # author { # name # } # } # } # } # ```