drf高级一

时间:2023-02-13 17:02:03

drf中有很多视图可以使用。APIView GenericAPIView是基础的两个视图。所有视图都是基于以上视图封装所得。

APIView

from rest_framework.views import APIView

继承自djangoView。是drf中最基础的一个视图类。能够实现基于类视图增删改查。相较于django的View增加了

  • responserenderer_classes
  • 请求参数解析parser_classes
  • 登录认证``authentication_classes
  • 权限认证permission_classes

而且修改了django的HttpRequestHttpResponse。原有的reqeust_request中。

class APIView(View):

    # The following policies may be set at either globally, or per-view.
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
    content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
    metadata_class = api_settings.DEFAULT_METADATA_CLASS
    versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

    # Allow dependency injection of other settings to make testing easier.
    settings = api_settings

    schema = DefaultSchema()

    @classmethod
    def as_view(cls, **initkwargs):
        """
        Store the original class on the view function.

        This allows us to discover information about the view when we do URL
        reverse lookups.  Used for breadcrumb generation.
        """
        if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
            def force_evaluation():
                raise RuntimeError(
                    'Do not evaluate the `.queryset` attribute directly, '
                    'as the result will be cached and reused between requests. '
                    'Use `.all()` or call `.get_queryset()` instead.'
                )
            cls.queryset._fetch_all = force_evaluation

        view = super().as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs

        # Note: session based authentication is explicitly CSRF validated,
        # all other authentication is CSRF exempt.
        return csrf_exempt(view)

上面是最核心的一段源码!drf增加了一部分能力。APIView类属性有常用的几个

注意api_settingsdrf默认配置。也可以在项目settings中*配置,这里的配置全局配置。类似APIView属于视图属性。

parser_classes

默认解析器

    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser'
    ],

REST 框架将检查传入请求上的标头,并确定使用哪个解析器来解析请求内容。request.data``Content-Type。请求参数

authentication_classes

默认session认证

    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication'
    ],

jwt认证安pip install djangorestframework-simplejwt。并增加配置

REST_FRAMEWORK = {
    ...
    'DEFAULT_AUTHENTICATION_CLASSES': (
        ...
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
    ...
}

djangorestframework-jwt有很长时间没有人维护,可以放弃了。而且simplejwt更加安全

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    ...
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    ...
]

simplejwt

permission_classes

默认匿名用户可以访问

    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ],

根据项目需求修改认证方式

from rest_framework.permissions import BasePermission


class CustomPermission(BasePermission):
    """权限"""

    def has_permission(self, request, view):
        return bool(request.user and request.user.is_authenticated)

    def has_object_permission(self, request, view, obj):
        return True

# 自定义权限
REST_FRAMEWORK = {
    ...
    'DEFAULT_PERMISSION_CLASSES': (
        ...
        'utils.permissions.CustomPermission',
    )
    ...
}

等。其中认证异常返回401,权限异常返回403

GenericAPIView

from rest_framework.generics import GenericAPIView

相较APIView增加了分页过滤。这个类是drf中的精髓,是*的减少代码的点。它结合了ORM序列化器过滤器让分页和过滤数据变得极度简单。所以,如果单纯的想写出一个分页的接口没有更多的业务需求可以使用它。

queryset

应用于从此视图返回对象的查询集。必须设置此属性或重写该方法。单个重写get_object多个重写get_queryset。这些结果将缓存用于所有后续请求。

serializer_class

应用于验证和反序列化输入以及序列化输出的序列化程序类, 同一个视图使用不同序列花器可以重写get_serializer_class方法,。必须设置此属性或重写该方法。get_serializerget_serializer_class基础上增加了kwargs.setdefault('context', self.get_serializer_context())。使你在序列化器中可以使用request

    def get_serializer_context(self):
        """
        Extra context provided to the serializer class.
        """
        return {
            'request': self.request,
            'format': self.format_kwarg,
            'view': self
        }

分页

分页是在django的from django.core.paginator import Paginator,结合QuerySet进行了一定的封装。其实,Paginator也可以对有序的可迭代对象进行所谓的分页

from rest_framework.pagination import PageNumberPagination


class CustomPagination(PageNumberPagination):
  	# 每页最大返回条数
    max_page_size = 100
    # 如果设置,则这是一个字符串值,指示允许客户端基于每个请求设置页面大小的查询参数的名称。默认值为 None,表示客户端可能无法控请求的页面大小
    page_size_query_param = 'page_size'
    # 每页条数
    page_size = 15
    # page_query_param- 一个字符串值,指示要用于分页控件的查询参数的名称。默认为page
    page_query_parma = 'page'

应用全局

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'utils.pagination.CustomPagination',
}

默认返回格式

{
    "count": 1023,
    "next": "https://api.example.org/accounts/?limit=100&offset=500",
    "previous": "https://api.example.org/accounts/?limit=100&offset=300",
    "results": [
       …
    ]
}

其实,如果返回的样式或者字段没有符合你的审美,可以在进行简单的修改。PageNumberPagination方法返回源码,默认返回一个有序的字典(虽然高版本的字典是有序的,不是很习惯)。

    def get_paginated_response(self, data):
        return Response(OrderedDict([
            ('count', self.page.paginator.count),
            ('next', self.get_next_link()),
            ('previous', self.get_previous_link()),
            ('results', data)
        ]))

过滤

filter_backends默认为[]。过滤一般需要借助另外一个包django_filters。它是一个强大的包,更多可以参照

如果您只需要简单的基于相等的过滤,则可以在视图或视图集上设置属性,列出要过滤的字段集。filterset_fields

class ProductList(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['category', 'in_stock']

这将自动为给定字段创建一个类,并允许您发出请求,例如:FilterSet

http://example.com/api/products?category=clothing&in_stock=True

对于更高级的筛选要求,您可以指定视图应使用的类。 你可以在 django 过滤器文档中阅读更多信息。 有关 DRF 集成的部分。FilterSet``FilterSet