Django REST Framework Views - APIViews
Фреймворк Django REST Framework (DRF) имеет свой собственный набор представлений, которые наследуются от класса View
Django. В этой серии из трех частей подробно рассматриваются все возможности DRF view - от простого представления, где многое приходится делать самостоятельно, до ModelViewSet
, где вы можете настроить представление и запустить его с помощью всего нескольких строк кода. Поскольку виды построены один поверх другого, в этой серии также объясняется, как они переплетаются.
В этой статье мы рассмотрим, как работают представления DRF, и познакомимся с самыми основными представлениями, APIView
.
Серия просмотров фреймворка Django REST:
Цели
К концу этой статьи вы должны уметь:
- Объясните, как работают представления DRF
- Объясните назначение класса
APIView
и чем он отличается от классаView
в Django - Используйте представления, основанные на функциях и классах
- Используйте декораторы политик (для представлений, основанных на функциях) и атрибуты политик (для представлений, основанных на классах)
Представления DRF
Важным компонентом представлений DRF является класс APIView
, который является подклассом класса View
в Django.
APIView
класс является основой для всех представлений, которые вы можете использовать в своем проекте приложения.
Будь то-
- представления, основанные на функциях
- представления, основанные на классах
- миксины
- общие классы представлений
- наборы представлений
- все они используют класс APIView
.
Как вы можете видеть из приведенного ниже изображения, возможности, которыми вы располагаете в отношении видов DRF, переплетаются и дополняют друг друга. Вы можете рассматривать виды как строительные блоки, которые образуют более крупные строительные блоки. При этом вы, вероятно, будете использовать некоторые строительные блоки, такие как представления API, конкретные представления и (только для чтения) наборы Modelviews, чаще, чем другие, такие как mixins и GenericViewSets. Конечно, все это зависит от потребностей вашего конкретного приложения.
Расширение APIView
обеспечивает максимальную свободу действий, но также оставляет для вас гораздо больше работы. Это отличный выбор, если вам нужно контролировать каждый аспект изображения или если у вас очень сложные изображения.
С помощью универсальных классов представления вы можете разрабатывать быстрее и при этом сохранять некоторый контроль над конечными точками API.
С помощью ModelViewSet
s вы можете настроить API с помощью пяти строк кода (три для ваших представлений, две для URL-адресов).
Все вышеупомянутые виды также можно настроить.
Правильного ответа на вопрос, что использовать, нет. Вам даже не обязательно использовать один и тот же тип представления в одном приложении; вы можете комбинировать их по своему усмотрению. Тем не менее, хорошо быть предсказуемым, поэтому отклоняйтесь от типа представления только тогда, когда это абсолютно необходимо.
В документации представления DRF разделены на три части. Статьи в этой серии имеют одинаковую структуру.
- Документация для APIViews (часть 1 этой серии)
- Документация для общих представлений (часть 2 этой серии)
- Документация по наборам представлений (часть 3 этой серии)
Стоит отметить, что в официальной документации каждое представление рассматривается как отдельная глава, а не как подразделы одной главы Views, как вы могли бы ожидать.
Наряду с руководством по API, у вас также есть официальное руководство, которое охватывает все три вида:
Давайте начнем с самого простого представления, APIView
, за которым последует объяснение того, как работает это представление.
Представления на основе классов
Представления на основе классов расширяют класс APIView
. С их помощью вы определяете, как будут обрабатываться запросы и какие атрибуты политики вы собираетесь использовать.
Например, предположим, что у вас есть класс Item
для вашего API списка покупок:
class Item(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
name = models.CharField(max_length=100)
done = models.BooleanField()
Вот представление, которое позволяет пользователям удалять все элементы сразу:
from rest_framework.response import Response
from rest_framework.views import APIView
class DeleteAllItems(APIView):
def delete(self, request):
Item.objects.all().delete()
return Response(status=status.HTTP_204_NO_CONTENT)
И вот представление, в котором перечислены все элементы:
from rest_framework.response import Response
from rest_framework.views import APIView
class ListItems(APIView):
def get(self, request):
items = Item.objects.all()
serializer = ItemSerializer(items, many=True)
return Response(serializer.data)
Как вы можете видеть, вызов базы данных выполняется внутри функций-обработчиков. Они выбираются в соответствии с HTTP-методом запроса (например, GET -> gt, DELETE -> удалить).
Вскоре мы подробнее расскажем о том, как работают эти представления.
Как вы можете видеть, мы установили сериализатор во втором представлении. Сериализаторы отвечают за преобразование сложных данных (например, наборов запросов и экземпляров моделей) в собственные типы данных Python, которые затем могут быть преобразованы в JSON, XML или другие типы контента.
Вы можете узнать больше о сериализаторах DRF в статье Эффективное использование сериализаторов Django REST Framework.
Атрибуты политики
Если вы хотите переопределить настройки по умолчанию для ваших представлений на основе классов, вы можете использовать атрибуты политики.
Можно задать следующие атрибуты политики:
Attribute | Usage | Examples |
---|---|---|
renderer_classes |
determines which media types the response returns | JSONRenderer , BrowsableAPIRenderer |
parser_classes |
determines which data parsers for different media types are allowed | JSONParser , FileUploadParser |
authentication_classes |
determines which authentication schemas are allowed for identifying the user | TokenAuthentication , SessionAuthentication |
throttle_classes |
determines if a request should be authorized based on the rate of requests | AnonRateThrottle , UserRateThrottle |
permission_classes |
determines if a request should be authorized based on user credentials | IsAuthenticated , DjangoModelPermissions |
content_negotiation_class |
selects one of the multiple possible representations of the resource to return to a client (unlikely you'll want to set it up) | only custom content negotiation classes |
Обязательно ознакомьтесь со статьей Пользовательские классы разрешений в Django REST Framework, чтобы узнать больше о классах разрешений.
В следующем примере мы изменили разрешения и способ отображения ответа с помощью атрибутов политики permission_classes
и renderer_classes
:
from rest_framework.permissions import IsAuthenticated
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
class ItemsNotDone(APIView):
permission_classes = [IsAuthenticated] # policy attribute
renderer_classes = [JSONRenderer] # policy attribute
def get(self, request):
user_count = Item.objects.filter(done=False).count()
content = {'not_done': user_count}
return Response(content)
Представления на основе функций
Существует два способа прямой реализации APIView
: с помощью функции или с помощью класса. Если вы пишете представление в виде функции, вам нужно будет использовать @api_view
декоратор.
@api_view
это декоратор, который преобразует функциональное представление в APIView
подкласс (таким образом, предоставляя классы Response
и Request
). В качестве аргумента он принимает список разрешенных методов для представления.
Интересно, как DRF преобразует представления на основе функций в подклассы APIView?
# https://github.com/encode/django-rest-framework/blob/3.12.4/rest_framework/decorators.py#L16 def api_view(http_method_names=None): http_method_names = ['GET'] if (http_method_names is None) else http_method_names def decorator(func): WrappedAPIView = type( 'WrappedAPIView', (APIView,), {'__doc__': func.__doc__} ) # ... return WrappedAPIView.as_view()
Вот функциональное представление, которое выполняет те же действия, что и ранее описанное классовое представление, для удаления всех элементов:
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['DELETE'])
def delete_all_items(request):
Item.objects.all().delete()
return Response(status=status.HTTP_200_OK)
Здесь мы преобразовали delete_all_items
в APIView
подкласс с помощью @api_view
декоратора. Разрешен только метод DELETE
. Другие методы выдадут сообщение "Метод 405 не разрешен".
Несмотря на разницу между тем, как записываются класс и функция, у нас есть доступ к одним и тем же свойствам, поэтому оба фрагмента кода дают одинаковый результат.
Декораторы политик
Если вы хотите изменить настройки по умолчанию для вашего функционального представления, вы можете использовать декораторы политик. Вы можете использовать одно или несколько из следующих действий:
@renderer_classes
@parser_classes
@authentication_classes
@throttle_classes
@permission_classes
Эти декораторы соответствуют подклассам APIView. Поскольку @api_view
декоратор проверяет, используется ли какой-либо из следующих декораторов, их необходимо добавить ниже декоратора api_view
.
Если мы используем тот же пример, что и для атрибутов политики, мы можем реализовать декораторы следующим образом для достижения тех же результатов:
from rest_framework.decorators import api_view, permission_classes, renderer_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
@api_view(['GET'])
@permission_classes([IsAuthenticated]) # policy decorator
@renderer_classes([JSONRenderer]) # policy decorator
def items_not_done(request):
user_count = Item.objects.filter(done=False).count()
content = {'not_done': user_count}
return Response(content)
Как работают представления DRF?
Когда запрос попадает в представление, оно сначала инициализирует объект Request, который является усовершенствованным DRF HttpRequest
из Django.
По сравнению с HttpRequest
в Django, он имеет следующие преимущества:
- Содержимое автоматически анализируется в соответствии с заголовком
Content-Type
и доступно в видеrequest.data
. - Он поддерживает методы PUT и PATCH (включая загрузку файлов)). ( Django поддерживает только методы
GET
иPOST
.) - Временно переопределяя метод в запросе, он проверяет разрешения на другие HTTP-методы.
После создания экземпляра Request
представление сохраняет принятую информацию в запросе, используя предоставленный (или используемый по умолчанию) механизм согласования содержимого и средства визуализации. После этого представление выполняет аутентификацию, а затем проверяет разрешения и любые ограничения.
Сама по себе аутентификация не возвращает никаких ошибок. Она просто определяет, кто является пользователем запроса. Эта информация требуется для проверки разрешений и регулирования. При проверке разрешений, если аутентификация не была успешной, возникает исключение NotAuthenticated
. Если запрос не разрешен, возникает исключение PermissionDenied
. При проверке регулирования, если запрос регулируется, генерируется исключение Throttled
, и пользователь получает уведомление о том, как долго ему нужно ждать разрешения запроса.
Проверка прав доступа на самом деле состоит из двух частей: check_permissions
и check_object_permissions
.
check_permissions
, который охватывает общие разрешения, вызывается перед выполнением обработчика представления. Если вы только расширяете APIView
, check_object_permissions
, то не выполняется, если вы явно не вызовете его. Если вы используете общие представления или наборы представлений, check_object_permissions
вызывается для подробных представлений.
Подробнее о разрешениях DRF читайте в статье Разрешения в Django REST Framework.
После проверки подлинности, авторизации/разрешений и регулирования в представлении проверяется, является ли метод запроса одним из следующих:
- get
- post
- put
- patch
- delete
- head
- option
- trace
Если это так, он проверяет, соответствует ли метод запроса методу в вашем представлении, и выполняет его. Если какой-либо из методов запрещен или не определен в вызываемом представлении, возникает исключение MethodNotAllowed
.
Метод dispatch
в классе APIView
проверяет метод и выбирает обработчик на основе имени метода:
# https://github.com/encode/django-rest-framework/blob/3.12.4/rest_framework/views.py#L485
class APIView(View):
# ...
def dispatch(self, request, *args, **kwargs):
# ...
try:
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
Разрешенные методы не определены в DRF, а взяты из Django:
# https://github.com/django/django/blob/stable/3.2.x/django/views/generic/base.py#L36
class View:
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
Наконец, вместо HttpResponse
в Django возвращается объект Response. Разница между HttpResponse
в Django и Response
в DRF заключается в том, что Response
инициализируется данными без визуализации, что позволяет отображать содержимое в нескольких типах в зависимости от запроса клиента.
Заключение
В DRF существует несколько типов представлений. Наиболее широко используемые из них:
- представления на основе классов, расширяющие
APIView
класс - конкретные представления
ModelViewSet
Они различаются по тому, насколько легко их настраивать, и по простоте использования. Вы устанавливаете политики (например, регулирование, разрешения) внутри представления, для представлений на основе классов, или с помощью декораторов, для представлений на основе функций.
Расширение APIView
дает вам максимальную свободу в настройке того, что происходит в самом представлении.
Глубокое погружение в серию просмотров фреймворка Django REST:
Вернуться на верх