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! Фильтрация сделает интерфейс гибким, а сортировка позволит находить важную информацию быстрее.

1
Задача
Модуль 3: Django, 25 уровень, 5 лекция
Недоступна
Фильтрация пользователей по нескольким параметрам
Фильтрация пользователей по нескольким параметрам
1
Задача
Модуль 3: Django, 25 уровень, 5 лекция
Недоступна
Фильтрация и сортировка
Фильтрация и сортировка
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ