Общие представления¶
Общие представления Django… были разработаны как кратчайший путь к общим шаблонам использования… Они берут определенные общие идиомы и шаблоны, встречающиеся в разработке представлений, и абстрагируют их так, чтобы вы могли быстро писать общие представления данных без необходимости повторяться.
‒ Django Documentation
Одним из ключевых преимуществ представлений на основе классов является то, что они позволяют вам компоновать кусочки многократно используемого поведения. Фреймворк REST использует это преимущество, предоставляя ряд готовых представлений, которые обеспечивают часто используемые шаблоны.
Типовые представления, предоставляемые REST-фреймворком, позволяют быстро создавать представления API, которые тесно связаны с моделями вашей базы данных.
Если типовые представления не соответствуют потребностям вашего API, вы можете перейти к использованию обычного класса APIView
, или повторно использовать миксины и базовые классы, используемые типовыми представлениями, чтобы составить свой собственный набор многократно используемых типовых представлений.
Примеры¶
Обычно при использовании общих представлений вы переопределяете представление и устанавливаете несколько атрибутов класса.
from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from rest_framework import generics
from rest_framework.permissions import IsAdminUser
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAdminUser]
Для более сложных случаев вы также можете захотеть переопределить различные методы класса представления. Например.
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAdminUser]
def list(self, request):
# Note the use of `get_queryset()` instead of `self.queryset`
queryset = self.get_queryset()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
Для очень простых случаев вы можете передать любые атрибуты класса с помощью метода .as_view()
. Например, ваша URLconf может включать что-то вроде следующей записи:
path('users/', ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list')
Справочник по API¶
GenericAPIView¶
Этот класс расширяет класс APIView
фреймворка REST, добавляя часто требуемое поведение для стандартных представлений списка и детализации.
Каждое из конкретных общих представлений создается путем объединения GenericAPIView
, с одним или несколькими классами-миксинами.
Атрибуты¶
Основные параметры :
Следующие атрибуты управляют основным поведением представления.
queryset
- Набор запросов, который должен использоваться для возврата объектов из данного представления. Как правило, вы должны либо установить этот атрибут, либо переопределить методget_queryset()
. Если вы переопределяете метод представления, важно, чтобы вы вызывалиget_queryset()
, а не обращались к этому свойству напрямую, так какqueryset
будет оценен один раз, и эти результаты будут кэшироваться для всех последующих запросов.serializer_class
- Класс сериализатора, который должен использоваться для проверки и десериализации ввода, а также для сериализации вывода. Как правило, вы должны либо установить этот атрибут, либо переопределить методget_serializer_class()
.lookup_field
- Поле модели, которое должно использоваться для выполнения поиска объектов отдельных экземпляров модели. По умолчанию'pk'
. Обратите внимание, что при использовании API с гиперссылками вам нужно убедиться, что и представления API, и классы сериализатора устанавливают поля поиска, если вам нужно использовать пользовательское значение.lookup_url_kwarg
- Аргумент ключевого слова URL, который должен использоваться для поиска объекта. URL conf должен включать аргумент ключевого слова, соответствующий этому значению. Если значение не установлено, то по умолчанию используется то же значение, что иlookup_field
.
Пагинация :
Следующие атрибуты используются для управления пагинацией при использовании представлений списка.
pagination_class
- Класс пагинации, который должен использоваться при пагинации результатов списка. По умолчанию имеет то же значение, что и параметрDEFAULT_PAGINATION_CLASS
, то есть'rest_framework.pagination.PageNumberPagination'
. Установкаpagination_class=None
отключает пагинацию в этом представлении.
Фильтрация :
filter_backends
- Список классов бэкенда фильтрации, которые должны использоваться для фильтрации набора запросов. По умолчанию имеет то же значение, что и параметрDEFAULT_FILTER_BACKENDS
.
Методы¶
Базовые методы :
get_queryset(self)
¶
Возвращает кверисет, который должен использоваться для списочных представлений и который должен использоваться в качестве базы для поиска в детальных представлениях. По умолчанию возвращается кверисет, указанный атрибутом queryset
.
Этот метод всегда следует использовать вместо прямого доступа к self.queryset
, так как self.queryset
оценивается только один раз, и эти результаты кэшируются для всех последующих запросов.
Может быть переопределена для обеспечения динамического поведения, например, возврата набора запросов, специфичного для пользователя, делающего запрос.
Например:
def get_queryset(self):
user = self.request.user
return user.accounts.all()
get_object(self)
¶
Возвращает экземпляр объекта, который должен использоваться для детальных представлений. По умолчанию используется параметр lookup_field
для фильтрации базового набора запросов.
Может быть переопределена для обеспечения более сложного поведения, например, поиска объектов на основе более чем одного URL kwarg.
Например:
def get_object(self):
queryset = self.get_queryset()
filter = {}
for field in self.multiple_lookup_fields:
filter[field] = self.kwargs[field]
obj = get_object_or_404(queryset, **filter)
self.check_object_permissions(self.request, obj)
return obj
Обратите внимание, что если ваш API не включает никаких разрешений на уровне объекта, вы можете исключить self.check_object_permissions
, и просто вернуть объект из поиска get_object_or_404
.
filter_queryset(self, queryset)
¶
Получив набор запросов, отфильтруйте его с помощью тех бэкендов фильтрации, которые используются, и верните новый набор запросов.
Например:
def filter_queryset(self, queryset):
filter_backends = [CategoryFilter]
if 'geo_route' in self.request.query_params:
filter_backends = [GeoRouteFilter, CategoryFilter]
elif 'geo_point' in self.request.query_params:
filter_backends = [GeoPointFilter, CategoryFilter]
for backend in list(filter_backends):
queryset = backend().filter_queryset(self.request, queryset, view=self)
return queryset
get_serializer_class(self)
¶
Возвращает класс, который должен быть использован для сериализатора. По умолчанию возвращает атрибут serializer_class
.
Может быть переопределен для обеспечения динамического поведения, например, использования различных сериализаторов для операций чтения и записи, или предоставления различных сериализаторов различным типам пользователей.
Например:
def get_serializer_class(self):
if self.request.user.is_staff:
return FullAccountSerializer
return BasicAccountSerializer
Сохранение и удаление крючков :
Следующие методы предоставляются классами mixin и обеспечивают легкое переопределение поведения сохранения или удаления объекта.
perform_create(self, serializer)
- ВызываетсяCreateModelMixin
при сохранении нового экземпляра объекта.perform_update(self, serializer)
- ВызываетсяUpdateModelMixin
при сохранении существующего экземпляра объекта.perform_destroy(self, instance)
- ВызываетсяDestroyModelMixin
при удалении экземпляра объекта.
Эти крючки особенно полезны для установки атрибутов, которые неявно присутствуют в запросе, но не являются частью данных запроса. Например, вы можете установить атрибут объекта на основе пользователя запроса или на основе аргумента ключевого слова URL.
def perform_create(self, serializer):
serializer.save(user=self.request.user)
Эти точки переопределения также особенно полезны для добавления поведения, которое происходит до или после сохранения объекта, например, отправки подтверждения по электронной почте или регистрации обновления.
def perform_update(self, serializer):
instance = serializer.save()
send_email_confirmation(user=self.request.user, modified=instance)
Вы также можете использовать эти крючки для обеспечения дополнительной проверки, вызывая сигнал ValidationError()
. Это может быть полезно, если вам нужно применить некоторую логику проверки в момент сохранения базы данных. Например:
def perform_create(self, serializer):
queryset = SignupRequest.objects.filter(user=self.request.user)
if queryset.exists():
raise ValidationError('You have already signed up')
serializer.save(user=self.request.user)
Другие методы :
Как правило, вам не нужно переопределять следующие методы, хотя вам может понадобиться обращаться к ним, если вы пишете пользовательские представления, используя GenericAPIView
.
get_serializer_context(self)
- Возвращает словарь, содержащий любой дополнительный контекст, который должен быть предоставлен сериализатору. По умолчанию включает'request'
,'view'
и'format'
ключи.get_serializer(self, instance=None, data=None, many=False, partial=False)
- Возвращает экземпляр сериализатора.get_paginated_response(self, data)
- Возвращает пагинационный объект стиляResponse
.paginate_queryset(self, queryset)
- Разбить набор запросов на страницы, если требуется, либо возвращая объект страницы, либоNone
, если разделение на страницы не настроено для данного представления.filter_queryset(self, queryset)
- Получив набор запросов, отфильтруйте его с помощью любых используемых бэкендов фильтрации, возвращая новый набор запросов.
Миксины¶
Классы-миксины предоставляют действия, которые используются для обеспечения базового поведения представления. Обратите внимание, что классы mixin предоставляют методы действий, а не определяют методы обработчиков, такие как .get()
и .post()
, напрямую. Это позволяет более гибко компоновать поведение.
Классы mixin могут быть импортированы из rest_framework.mixins
.
ListModelMixin¶
Предоставляет метод .list(request, *args, **kwargs)
, который реализует перечисление набора запросов.
Если набор запросов заполнен, возвращается ответ 200 OK
, в теле которого находится сериализованное представление набора запросов. По желанию данные ответа могут быть постраничными.
CreateModelMixin¶
Предоставляет метод .create(request, *args, **kwargs)
, который реализует создание и сохранение нового экземпляра модели.
Если объект создан, то возвращается ответ 201 Created
с сериализованным представлением объекта в качестве тела ответа. Если представление содержит ключ с именем url
, то заголовок Location
ответа будет заполнен этим значением.
Если данные запроса, предоставленные для создания объекта, оказались недействительными, будет возвращен ответ 400 Bad Request
, в теле которого будет содержаться информация об ошибке.
RetrieveModelMixin¶
Предоставляет метод .retrieve(request, *args, **kwargs)
, который реализует возврат существующего экземпляра модели в ответ.
Если объект может быть получен, то возвращается ответ 200 OK
, с сериализованным представлением объекта в качестве тела ответа. В противном случае возвращается 404 Not Found
.
UpdateModelMixin¶
Предоставляет метод .update(request, *args, **kwargs)
, который реализует обновление и сохранение существующего экземпляра модели.
Также предусмотрен метод .partial_update(request, *args, **kwargs)
, который аналогичен методу update
, за исключением того, что все поля для обновления будут необязательными. Это позволяет поддерживать HTTP PATCH
запросы.
Если объект обновлен, возвращается ответ 200 OK
с сериализованным представлением объекта в качестве тела ответа.
Если данные запроса, предоставленные для обновления объекта, оказались недействительными, будет возвращен ответ 400 Bad Request
, в теле которого будет содержаться информация об ошибке.
DestroyModelMixin¶
Предоставляет метод .destroy(request, *args, **kwargs)
, который реализует удаление существующего экземпляра модели.
Если объект удален, возвращается ответ 204 No Content
, в противном случае возвращается ответ 404 Not Found
.
Занятия по просмотру бетона¶
Следующие классы - это конкретные общие представления. Если вы используете общие представления, то обычно вы работаете именно на этом уровне, если только вам не нужно сильно измененное поведение.
Классы представления могут быть импортированы из rest_framework.generics
.
CreateAPIView¶
Используется только для создания конечных точек.
Предоставляет обработчик метода post
.
Расширяется: GenericAPIView
ListAPIView¶
Используется для конечных точек только для чтения для представления коллекции экземпляров модели.
Предоставляет обработчик метода get
.
Расширяется: GenericAPIView
RetrieveAPIView¶
Используется для конечных точек только для чтения для представления одного экземпляра модели.
Предоставляет обработчик метода get
.
Расширяется: GenericAPIView
DestroyAPIView¶
Используется для только для удаления конечных точек для одного экземпляра модели.
Предоставляет обработчик метода delete
.
Расширяется: GenericAPIView
UpdateAPIView¶
Используется для только для обновления конечных точек для одного экземпляра модели.
Предоставляет обработчики методов put
и patch
.
Расширяется: GenericAPIView
ListCreateAPIView¶
Используется для конечных точек чтения-записи для представления коллекции экземпляров модели.
Предоставляет обработчики методов get
и post
.
Расширяется: GenericAPIView
RetrieveUpdateAPIView¶
Используется для чтения или обновления конечных точек для представления одного экземпляра модели.
Предоставляет обработчики методов get
, put
и patch
.
Расширяется: GenericAPIView
RetrieveDestroyAPIView¶
Используется для конечных точек чтения или удаления для представления одного экземпляра модели.
Предоставляет обработчики методов get
и delete
.
Расширяется: GenericAPIView
RetrieveUpdateDestroyAPIView¶
Используется для конечных точек чтение-запись-удаление для представления одного экземпляра модели.
Предоставляет обработчики методов get
, put
, patch
и delete
.
Расширяется: GenericAPIView
Настройка общих представлений¶
Часто вы хотите использовать существующие типовые представления, но при этом использовать несколько измененное поведение. Если вы столкнулись с повторным использованием некоторого настроенного поведения в нескольких местах, вы, возможно, захотите рефакторизовать это поведение в общий класс, который затем можно будет просто применить к любому представлению или набору представлений по мере необходимости.
Создание пользовательских миксинов¶
Например, если вам нужно искать объекты на основе нескольких полей в URL conf, вы можете создать класс mixin, подобный следующему:
class MultipleFieldLookupMixin:
"""
Apply this mixin to any view or viewset to get multiple field filtering
based on a `lookup_fields` attribute, instead of the default single field filtering.
"""
def get_object(self):
queryset = self.get_queryset() # Get the base queryset
queryset = self.filter_queryset(queryset) # Apply any filter backends
filter = {}
for field in self.lookup_fields:
if self.kwargs[field]: # Ignore empty fields.
filter[field] = self.kwargs[field]
obj = get_object_or_404(queryset, **filter) # Lookup the object
self.check_object_permissions(self.request, obj)
return obj
Затем вы можете просто применить этот миксин к представлению или набору представлений в любое время, когда вам нужно применить пользовательское поведение.
class RetrieveUserView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
lookup_fields = ['account', 'username']
Использование пользовательских миксинов - хороший вариант, если у вас есть пользовательское поведение, которое необходимо использовать.
Создание пользовательских базовых классов¶
Если вы используете миксин в нескольких представлениях, вы можете пойти дальше и создать свой собственный набор базовых представлений, которые затем можно использовать во всем проекте. Например:
class BaseRetrieveView(MultipleFieldLookupMixin,
generics.RetrieveAPIView):
pass
class BaseRetrieveUpdateDestroyView(MultipleFieldLookupMixin,
generics.RetrieveUpdateDestroyAPIView):
pass
Использование пользовательских базовых классов является хорошим вариантом, если у вас есть пользовательское поведение, которое последовательно должно повторяться в большом количестве представлений в вашем проекте.
PUT как создать¶
До версии 3.0 миксины фреймворка REST рассматривали PUT
как операцию обновления или создания, в зависимости от того, существовал ли уже объект или нет.
Разрешение PUT
в качестве операций создания является проблематичным, поскольку оно обязательно раскрывает информацию о существовании или несуществовании объектов. Также не очевидно, что прозрачное разрешение повторного создания ранее удаленных экземпляров обязательно является лучшим поведением по умолчанию, чем простое возвращение ответов 404
.
Оба стиля «** PUT
as 404» и «** PUT
as create» могут быть действительны в различных обстоятельствах, но начиная с версии 3.0 мы используем поведение 404 по умолчанию, поскольку оно проще и очевиднее.
Если вам нужно универсальное поведение PUT-as-create, вы можете включить что-то вроде this ``AllowPUTAsCreateMixin:doc:` class <https://gist.github.com/tomchristie/a2ace4577eff2c603b1b>` в качестве миксина в ваши представления.
Пакеты сторонних производителей¶
Следующие пакеты сторонних производителей предоставляют дополнительные реализации общих представлений.
Django Rest Multiple Models¶
Django Rest Multiple Models предоставляет общее представление (и миксин) для отправки нескольких сериализованных моделей и/или наборов запросов через один запрос API.