Представьте, что у вас есть приложение для управления библиотекой (сколько книг вы начнёте читать одновременно?). Пользователь хочет увидеть книги по конкретному автору, отсортированные в возрастающем порядке по дате публикации. Если ваш 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! Фильтрация сделает интерфейс гибким, а сортировка позволит находить важную информацию быстрее.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ