JavaRush /Курси /Модуль 3: Django /Робота з фільтрацією та сортуванням даних у GraphQL

Робота з фільтрацією та сортуванням даних у GraphQL

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

Уявіть, що у вас є додаток для управління бібліотекою (скільки книг ви почнете читати одночасно?). Користувач хоче побачити книги конкретного автора, відсортовані у зростаючому порядку за датою публікації. Якщо ваш API не вміє фільтрувати дані та сортувати результати, користувачам доведеться витягувати ВСІ дані і обробляти їх на клієнтській стороні. Незручно? Та ще й ресурсоємно.

Фільтрація та сортування дозволяють:

  • Зменшити навантаження на мережу і прискорити завантаження сторінок.
  • Спростити обробку даних на клієнті.
  • Зробити API більш зручним та інтуїтивно зрозумілим для розробників.

Замість того, щоб надсилати тисячу рядків JSON і змушувати клієнта розбиратися, які з них йому потрібні, ви повернете лише ту інформацію, яка відповідає умовам запиту. Ми економимо ресурси сервера і нерви користувачів.

Основи фільтрації у GraphQL

Фільтрація у GraphQL досягається за допомогою додавання аргументів до запиту. Коли ви запитуєте ресурси, ви можете передати параметри, які описують умови відбору. Наприклад, ми можемо запитувати всіх користувачів старше 18 років або тільки книги конкретного жанру.

Приклад фільтрації: книги за жанром

Почнемо зі створення моделі Book у вашому додатку Django. Переконайтеся, що вона вже існує у вашому проєкті. Якщо її немає, створіть наступну модель:

# models.py

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=255)
    author = models.CharField(max_length=255)
    genre = models.CharField(max_length=100)
    publication_date = models.DateField()

    def __str__(self):
        return self.title

Тепер напишемо GraphQL схему для фільтрації книг за жанром. Ми додамо аргумент genre до нашого запиту.

# schema.py

from graphene import ObjectType, List, String, Field
from graphene_django.types import DjangoObjectType
from .models import Book

class BookType(DjangoObjectType):
    class Meta:
        model = Book

class Query(ObjectType):
    books = List(BookType, genre=String())

    def resolve_books(self, info, genre=None):
        if genre:
            return Book.objects.filter(genre=genre)
        return Book.objects.all()

Тепер запит у GraphQL може виглядати так:

query {
  books(genre: "Science Fiction") {
    title
    author
  }
}

Результат:

{
  "data": {
    "books": [
      {
        "title": "Dune",
        "author": "Frank Herbert"
      },
      {
        "title": "Foundation",
        "author": "Isaac Asimov"
      }
    ]
  }
}

Складні фільтри: комбінуємо умови

Що, якщо потрібно фільтрувати книги не тільки за жанром, але й за автором? Доповнимо наш резолвер, щоб він підтримував фільтрацію за декількома параметрами.

class Query(ObjectType):
    books = List(BookType, genre=String(), author=String())

    def resolve_books(self, info, genre=None, author=None):
        queryset = Book.objects.all()
        if genre:
            queryset = queryset.filter(genre=genre)
        if author:
            queryset = queryset.filter(author=author)
        return queryset

Приклад запиту:

query {
  books(genre: "Science Fiction", author: "Isaac Asimov") {
    title
    publicationDate
  }
}

Основи сортування даних у GraphQL

Сортування керує порядком, у якому повертаються результати. Ви можете використовувати його для впорядкування даних за датою, ім'ям або будь-яким іншим полем. У GraphQL це зазвичай досягається за допомогою аргументу order_by (або подібного, залежно від ваших уподобань).

Для реалізації сортування за одним полем додамо аргумент order_by у наш запит. Оновимо схему так:

class Query(ObjectType):
    books = List(BookType, genre=String(), order_by=String())

    def resolve_books(self, info, genre=None, order_by=None):
        queryset = Book.objects.all()
        if genre:
            queryset = queryset.filter(genre=genre)
        if order_by:
            queryset = queryset.order_by(order_by)
        return queryset

Тепер можна запитати книги, відсортувавши їх за назвою:

query {
  books(orderBy: "title") {
    title
    author
  }
}

Або у зворотному порядку:

query {
  books(orderBy: "-publication_date") {
    title
    publicationDate
  }
}

Зверніть увагу, що знак - перед назвою поля означає зворотний порядок сортування.

Сортування за кількома полями

У деяких випадках може знадобитися сортування одразу за кількома полями. Наприклад, спочатку відсортувати за датою публікації, а потім — за назвою.

Ми додамо підтримку списку аргументів для order_by:

class Query(ObjectType):
    books = List(BookType, genre=String(), order_by=List(String))

    def resolve_books(self, info, genre=None, order_by=None):
        queryset = Book.objects.all()
        if genre:
            queryset = queryset.filter(genre=genre)
        if order_by:
            queryset = queryset.order_by(*order_by)
        return queryset

Приклад запиту:

query {
  books(orderBy: ["publication_date", "title"]) {
    title
    publicationDate
  }
}

Комбінуємо фільтрацію та сортування

Тепер давайте об'єднаємо фільтрацію та сортування в одному запиті. Це дозволить користувачу, наприклад, отримати всі книги певного жанру, відсортовані за датою публікації.

query {
  books(genre: "Fantasy", orderBy: "publication_date") {
    title
    author
    publicationDate
  }
}

Цей запит поверне всі книги жанру "Fantasy" у порядку їх публікації.

Інтеграція з DjangoFilterBackend для складної фільтрації

Хоча ми вже навчилися додавати фільтрацію вручну, у реальних проєктах простіше підключити DjangoFilterBackend. Це дасть нам можливість швидко створювати складні фільтри, такі як діапазони дат, пошук за підрядком тощо.

Встановіть бібліотеку django-filter:

pip install django-filter

Налаштуємо фільтр у схемі:

from django_filters import FilterSet, CharFilter, DateFilter
from graphene_django.filter import DjangoFilterConnectionField

class BookFilter(FilterSet):
    title_contains = CharFilter(field_name="title", lookup_expr="icontains")
    publication_date_after = DateFilter(field_name="publication_date", lookup_expr="gte")

    class Meta:
        model = Book
        fields = ["genre", "author"]

class Query(ObjectType):
    books = DjangoFilterConnectionField(BookType, filterset_class=BookFilter)

Тепер на клієнті можна використовувати фільтри:

query {
  books(genre: "Fantasy", titleContains: "Harry", publicationDateAfter: "1990-01-01") {
    title
    author
    publicationDate
  }
}

Ваші користувачі тепер зможуть без проблем фільтрувати та сортувати дані через API! Фільтрація зробить інтерфейс гнучким, а сортування дозволить знаходити важливу інформацію швидше.

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