JavaRush /Курси /Модуль 3: Django /Робота з Django моделями через GraphQL

Робота з Django моделями через GraphQL

Модуль 3: Django
Рівень 24 , Лекція 5
Відкрита

Що ж, тепер час зробити наступний крок — зв’язати наші Django-моделі (тобто базу даних) зі світом GraphQL. Уявіть, що API — це певний офіціант у ресторані, який доставляє дані до вашого столу. А Django моделі — це шеф-кухарі на кухні. Сьогодні ви навчитеся "передавати замовлення" між ними.

Попередні знання

Кілька слів для налаштування контексту. Ми припускаємо, що ви вже:

  1. Розумієте, що таке GraphQL: запити, мутації тощо.
  2. Успішно встановили Graphene-Django і налаштували базовий GraphQL API.
  3. Маєте Django проєкт із підключеною базою даних та хоча б однією робочою моделлю.

План на сьогодні

Ось що ми сьогодні вивчимо та випробуємо:

  1. Як зв'язати Django моделі з GraphQL.
  2. Використання DjangoObjectType для роботи з моделями.
  3. Отримання даних з бази через GraphQL.
  4. Приклад створення простого запиту, що працює з моделлю.
  5. Обговорення типових помилок та підводних каменів.

Інтеграція моделей 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, щоб переконатися, що вони повертають саме те, що ви очікуєте.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ