🔖 Справочник — Урок 31
⚡ Быстрый справочник
# Extract* — импорт
from django.db.models.functions import ExtractYear, ExtractMonth, ExtractQuarter
# Прямая фильтрация (lookups)
qs = Model.objects.filter(date_field__year=2023)
qs = Model.objects.filter(date_field__month=1)
qs = Model.objects.filter(date_field__quarter=2)
# Через annotate
qs = Model.objects.annotate(yr=ExtractYear('date_field')).filter(yr=2023)
# query_params в APIView
val = request.query_params.get('key') # None если нет
val = request.query_params.get('key', 'def') # дефолт
# Фильтрация через словарь
filters = {}
if author: filters['author'] = author
qs = Model.objects.filter(**filters)
# Сортировка
sort_by = request.query_params.get('sort_by', 'title')
sort_order = request.query_params.get('sort_order', 'asc')
if sort_order == 'desc': sort_by = f'-{sort_by}'
qs = qs.order_by(sort_by)
# Пагинация
results = self.paginate_queryset(qs, request, view=self)
return self.get_paginated_response(serializer.data)
Extract* — полная таблица функций
| Функция | Lookup-суффикс | Диапазон | Описание |
|---|---|---|---|
ExtractYear | __year | напр. 2023 | Год из даты/времени |
ExtractMonth | __month | 1–12 | Месяц из даты/времени |
ExtractDay | __day | 1–31 | День из даты/времени |
ExtractWeekDay | __week_day | 1–7 (1=вс) | День недели |
ExtractWeek | __week | 1–53 | Номер недели (ISO) |
ExtractQuarter | __quarter | 1–4 | Квартал года |
ExtractHour | __hour | 0–23 | Час из времени |
ExtractMinute | __minute | 0–59 | Минута из времени |
ExtractSecond | __second | 0–59 | Секунда из времени |
Синтаксис Extract*
Импорт
from django.db.models.functions import (
ExtractYear, ExtractMonth, ExtractDay,
ExtractWeekDay, ExtractWeek, ExtractQuarter,
ExtractHour, ExtractMinute, ExtractSecond
)
Прямые lookups (без импорта функций)
# Поле дата: published_date
Model.objects.filter(published_date__year=2023)
Model.objects.filter(published_date__month=1)
Model.objects.filter(published_date__quarter=2)
Model.objects.filter(published_date__week_day=3) # вторник
Model.objects.filter(published_date__week=10)
Model.objects.filter(created_at__hour=14) # DateTimeField
Аннотация + фильтрация
from django.db.models.functions import ExtractYear
qs = Model.objects.annotate(
yr=ExtractYear('published_date')
).filter(yr=2023)
# Аннотация для агрегации (группировка по году)
from django.db.models import Count
qs = Model.objects.annotate(
yr=ExtractYear('published_date')
).values('yr').annotate(total=Count('id')).order_by('yr')
request.query_params — синтаксис
# Получить одно значение
val = request.query_params.get('key') # None если нет
val = request.query_params.get('key', 'default') # значение по умолчанию
# Получить список значений (для параметра ?tags=a&tags=b)
vals = request.query_params.getlist('tags') # ['a', 'b']
# Проверить наличие параметра
if 'filter' in request.query_params:
...
# Получить все параметры как словарь
all_params = dict(request.query_params) # {'key': ['val'], ...}
Паттерн: динамическая фильтрация
class BookListView(APIView):
def get(self, request):
filters = {}
author = request.query_params.get('author')
pub_year = request.query_params.get('pub_year')
genre = request.query_params.get('genre')
if author:
filters['author__icontains'] = author # регистронезависимо
if pub_year and pub_year.isdigit():
filters['published_date__year'] = int(pub_year)
if genre:
filters['genre__name'] = genre
books = Book.objects.filter(**filters)
serializer = BookSerializer(books, many=True)
return Response(serializer.data)
Паттерн: сортировка
ALLOWED_SORT_FIELDS = {'title', 'price', 'published_date', 'author'}
class BookListView(APIView):
def get(self, request):
sort_by = request.query_params.get('sort_by', 'title')
sort_order = request.query_params.get('sort_order', 'asc')
# Валидация поля сортировки
if sort_by not in ALLOWED_SORT_FIELDS:
sort_by = 'title'
if sort_order == 'desc':
sort_by = f'-{sort_by}'
books = Book.objects.all().order_by(sort_by)
serializer = BookSerializer(books, many=True)
return Response(serializer.data)
Паттерн: пагинация в APIView
from rest_framework.pagination import PageNumberPagination
class BookListView(APIView, PageNumberPagination):
page_size = 10 # дефолтный размер страницы
page_size_query_param = 'page_size' # имя параметра в URL
max_page_size = 100 # максимальный размер
def get(self, request):
books = Book.objects.all()
results = self.paginate_queryset(books, request, view=self)
serializer = BookSerializer(results, many=True)
return self.get_paginated_response(serializer.data)
Атрибуты PageNumberPagination:
page_size— размер страницы по умолчаниюpage_size_query_param— имя URL-параметра для page_sizepage_query_param— имя параметра для номера страницы (по умолч.'page')max_page_size— максимально допустимый размер страницы
Объединённый паттерн: фильтрация + сортировка + пагинация
class BookListView(APIView, PageNumberPagination):
page_size = 10
def get(self, request):
filters = {}
author = request.query_params.get('author')
if author:
filters['author__icontains'] = author
sort_by = request.query_params.get('sort_by', 'title')
sort_order = request.query_params.get('sort_order', 'asc')
if sort_order == 'desc':
sort_by = f'-{sort_by}'
books = Book.objects.filter(**filters).order_by(sort_by)
results = self.paginate_queryset(books, request, view=self)
serializer = BookSerializer(results, many=True)
return self.get_paginated_response(serializer.data)