Общие представления

Общие представления 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.

Вернуться на верх