Что ж, теперь пора сделать следующий шаг — связать наши Django-модели (то есть базу данных) с миром GraphQL. Представьте, что API — это некий официант в ресторане, который доставляет данные к вашему столу. А Django модели — это шеф-повара на кухне. Сегодня вы научитесь "передавать заказы" между ними.
Предварительные знания
Пару слов для настройки контекста. Мы предполагаем, что вы уже:
- Понимаете, что такое GraphQL: запросы, мутации и др.
- Успешно установили Graphene-Django и настроили базовый GraphQL API.
- Имеете Django проект с подключённой базой данных и хотя бы одной рабочей моделью.
План на сегодня
Вот что мы сегодня изучим и опробуем:
- Как связать Django модели с GraphQL.
- Использование DjangoObjectType для работы с моделями.
- Получение данных из базы через GraphQL.
- Пример создания простого запроса, работающего с моделью.
- Обсуждение типичных ошибок и подводных камней.
Интеграция моделей Django с GraphQL
Одним из ключевых инструментов, которые делает Graphene-Django таким удобным, является класс DjangoObjectType. Этот класс выступает "мостом" между вашими Django моделями и GraphQL-типами. Важно понимать, что он автоматически создаёт типы на основе ваших моделей, что избавляет вас от необходимости делать это вручную.
Как это работает? На высоком уровне DjangoObjectType:
- Сканирует поля указанной модели.
- Преобразует эти поля в соответствующие GraphQL-типы.
- Добавляет в схему всё, что нужно для работы с данной моделью через API.
Использование DjangoObjectType для связки моделей и типов GraphQL
Давайте начнём с простой Django-модели Book. Мы предполагаем, что вы работаете над системой управления книгами (почему бы и нет, книги — это классика!).
# models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.CharField(max_length=100)
published_date = models.DateField()
price = models.DecimalField(max_digits=6, decimal_places=2)
def __str__(self):
return self.title
Эта модель описывает книги с полями: название, автор, дата публикации и цена.
Создание DjangoObjectType
Теперь мы создадим GraphQL-тип для этой модели. Откройте или создайте файл schema.py в вашем приложении:
# schema.py
import graphene
from graphene_django.types import DjangoObjectType
from .models import Book
class BookType(DjangoObjectType):
class Meta:
model = Book # Указываем, с какой моделью связать этот тип
fields = ("id", "title", "author", "published_date", "price") # Явно перечисляем нужные поля
Здесь мы использовали DjangoObjectType, чтобы создать GraphQL-тип на основе модели Book. Поля модели автоматически преобразуются в поля GraphQL.
Подключение к Query
Теперь добавим этот новый тип в наши запросы (Query). Вот как это выглядит:
# schema.py (добавление Query)
class Query(graphene.ObjectType):
all_books = graphene.List(BookType) # Запрос, который возвращает список книг
def resolve_all_books(root, info):
# Этот метод отвечает за получение данных
return Book.objects.all()
Свойство all_books добавляет возможность получить список всех книг. Функция resolve_all_books реализует логику получения данных из базы.
Настройка проекта
Не забудьте обновить schema.py проекта, чтобы связать эти запросы:
# core/schema.py (или в корне проекта, если вы используете схему на уровне всего проекта)
import graphene
import books.schema # books — ваше приложение
class Query(books.schema.Query, graphene.ObjectType):
pass
schema = graphene.Schema(query=Query)
Тестирование: получение данных через GraphQL
Теперь проверим, как работает наш API. Для этого поднимем сервер разработки:
python manage.py runserver
Откройте GraphiQL по адресу http://localhost:8000/graphql и выполните следующий запрос:
query {
allBooks {
id
title
author
publishedDate
price
}
}
Вы должны получить все книги из базы данных. Как минимум, пустой список, если в базе ещё ничего нет.
Добавление новых возможностей
Представьте, что вас просят добавить возможность получать книги по их ID. Что ж, вызов принят!
Мы добавим новый запрос book, который будет принимать аргумент id. Вот пример реализации:
class Query(graphene.ObjectType):
all_books = graphene.List(BookType)
book = graphene.Field(BookType, id=graphene.Int(required=True)) # Новый запрос
def resolve_all_books(root, info):
return Book.objects.all()
def resolve_book(root, info, id):
# Ищем книгу по переданному ID
try:
return Book.objects.get(pk=id)
except Book.DoesNotExist:
return None
Теперь в GraphiQL можно выполнить такой запрос:
query {
book(id: 1) {
title
author
price
}
}
Обратите внимание, что здесь мы добавили базовую обработку ошибок (если книги с указанным ID нет).
Ошибки и подводные камни
При работе с DjangoObjectType можно столкнуться с несколькими распространёнными проблемами.
Проблема 1: поле не отображается в GraphQL. Если вы добавили новое поле в модель, но оно не отображается в API, скорее всего, вы не упомянули это поле в fields класса Meta. Убедитесь, что оно явно перечислено.
Проблема 2: ошибка сериализации данных. Некоторые типы полей Django, например JSONField или FileField, могут вызывать ошибки, так как они не поддерживаются natively в GraphQL. Для таких случаев можно определить кастомное поле или преобразовать его в строку.
from django.db.models import JSONField
class MyModel(models.Model):
data = JSONField()
class MyModelType(DjangoObjectType):
class Meta:
model = MyModel
data_json = graphene.String()
def resolve_data_json(root, info):
return json.dumps(root.data) # Преобразование JSON в строку
Практическое применение
Работа с моделями через GraphQL позволяет вам:
- Быстро интегрировать существующие базы данных с новым API.
- Гибко управлять запросами и фильтрацией данных на уровне типа.
- Облегчить взаимодействие между фронтендом и бекендом.
Теперь вы можете разрабатывать более сложные запросы, обрабатывать входные данные и валидацию, а также оптимизировать взаимодействие с базой (например, через select_related() или prefetch_related()).
Совет: всегда тестируйте свои запросы в GraphiQL, чтобы убедиться, что они возвращают именно то, что вы ожидаете.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ