Ми навчилися використовувати базові класи пагінації в DRF, такі як PageNumberPagination і LimitOffsetPagination, а також кастомізували їх для більш гнучкого налаштування. Звідси й плавно переходимо до нашої нової теми: фільтрація даних. Бо, знаєте, мало даних порційно віддавати — добре б ще давати користувачеві тільки те, що йому потрібно, а не "все і одразу".
Фільтрація у DRF
Django REST Framework (DRF) підтримує фільтрацію даних прямо "з коробки". У DRF для фільтрації вже підготовлені механізми, такі як DjangoFilterBackend, SearchFilter і OrderingFilter. Ці інструменти можна комбінувати, щоб не просто фільтрувати дані, але й сортувати їх за полями API, а також шукати за конкретними значеннями. Ми почнемо з основ, а потім будемо рухатися до більш складних і кастомних сценаріїв.
Найпростіша ручна фільтрація
Почнемо з базового прикладу. Якщо раптом тобі не потрібно використовувати готові інструменти фільтрації або ти хочеш реалізувати щось просте, можна додати фільтрацію прямо в метод твого представлення.
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Product
class ProductListView(APIView):
def get(self, request):
# Отримуємо необроблені дані з моделі
products = Product.objects.all()
# Перевіряємо, чи є параметр фільтрації "category"
category = request.query_params.get('category')
if category:
products = products.filter(category=category)
# Перетворюємо дані в Python, щоб віддати їх клієнту
data = [{"id": p.id, "name": p.name, "category": p.category} for p in products]
return Response(data)
Тут відбувається наступне:
- Ми беремо всі записи з моделі
Product. - Перевіряємо, чи передав користувач параметр
categoryу рядку запиту (?category=some-category). - Якщо параметр є, фільтруємо дані за категорією.
Досить просто, чи не так? Однак якщо ти хочеш додати більше можливостей фільтрації, наприклад, фільтр за ціною, назвою, виробником, то твій код швидко перетвориться на кашу з умов. Тому для масштабованості краще звернутися за допомогою до інструментів DRF.
Підтримка фільтрації в DRF
DjangoFilterBackend— це вбудований інструмент DRF для роботи з фільтрацією. Він дозволяє підключити фільтрацію на рівні представлень і використовувати готові фільтри, які визначаються через спеціальні класи. Це робить код чистішим і дозволяє зосередитися на логіці.
Перш ніж ми почнемо з налаштування, переконайтеся, що у вас встановлена бібліотека django-filter. Якщо не встановлена, то вам на допомогу приходить команда:
pip install django-filter
Потім додайте django_filters до списку INSTALLED_APPS вашого settings.py:
INSTALLED_APPS = [
# Інші додатки
'django_filters',
]
Вуаля, тепер ми готові до фільтрації!
Налаштування фільтрації з DjangoFilterBackend
Для початку підключимо DjangoFilterBackend до нашого проєкту. У DRF бекенди фільтрації визначаються у налаштуванні DEFAULT_FILTER_BACKENDS у settings.py:
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
],
}
Це дозволяє задавати фільтри в будь-якому з ваших представлень.
Проста фільтрація
Використовуємо DjangoFilterBackend у нашому представленні. Припустимо, у нас є модель Product:
# models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
category = models.CharField(max_length=50)
price = models.DecimalField(max_digits=10, decimal_places=2)
Тепер додамо фільтрацію у представлення:
# views.py
from rest_framework.generics import ListAPIView
from django_filters.rest_framework import DjangoFilterBackend
from .models import Product
from .serializers import ProductSerializer
class ProductListView(ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = [DjangoFilterBackend] # Підключаємо бекенд фільтрації
filterset_fields = ['category', 'price'] # Вказуємо доступні поля фільтрації
Тепер ви можете звертатися до API за допомогою таких запитів:
GET /api/products?category=electronics—отримати всі продукти у категорії "electronics".GET /api/products?price=99.99—отримати всі продукти з ціною 99.99.
Як бачите, все вже працює! А ще код став чистішим, ніж у нашому базовому прикладі.
Кастомізація фільтрації з FilterSet
Якщо потрібно більше контролю над логікою фільтрації, можна створювати кастомні набори фільтрів (filter sets), використовуючи бібліотеку django-filter.
# filters.py
import django_filters
from .models import Product
class ProductFilter(django_filters.FilterSet):
min_price = django_filters.NumberFilter(field_name="price", lookup_expr='gte')
max_price = django_filters.NumberFilter(field_name="price", lookup_expr='lte')
class Meta:
model = Product
fields = ['category', 'min_price', 'max_price']
Ми додали два кастомні фільтри: min_price (ціна більше або дорівнює) і max_price (ціна менше або дорівнює). Тепер підключимо ці фільтри в нашому представленні:
# views.py
from .filters import ProductFilter
class ProductListView(ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = [DjangoFilterBackend]
filterset_class = ProductFilter # Вказуємо наш кастомний клас фільтрів
Тепер доступні фільтри на зразок:
GET /api/products?min_price=50&max_price=200—продукти з ціною між 50 і 200.GET /api/products?category=books&min_price=10—книги з ціною від 10.
Підказка про налагодження фільтрів
Одна з типових проблем при роботі з фільтрацією — це відсутність даних, тому що фільтр не спрацював. Якщо бачиш порожній список результатів, перш за все перевір:
- Що параметр фільтрації передається коректно
?category=something. - Що дані в базі відповідають значенню фільтра.
Якщо щось не сходиться, спробуй налагодити запит на стороні Django ORM: візьми отриманий QuerySet і виконай його у Django shell.
Переваги підходу
Фільтрація за допомогою DjangoFilterBackend значно спрощує життя:
- Чистий і зрозумілий код.
- Потужні можливості кастомізації.
- Швидка інтеграція фільтрів в API.
Рухаючись далі, ми заглибимось у додаткові можливості, такі як пошук, сортування та кастомні фільтри. Ми тільки почали розкривати потенціал фільтрації!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ