在drf
中有很多视图可以使用。APIView
GenericAPIView
是基础的两个视图。所有视图都是基于以上视图封装所得。
APIView
from rest_framework.views import APIView
继承自django
中View
。是drf
中最基础的一个视图类。能够实现基于类视图增删改查。相较于django的View
增加了
- response
renderer_classes
- 请求参数解析
parser_classes
- 登录认证``authentication_classes
- 权限认证
permission_classes
而且修改了django的HttpRequest
和HttpResponse
。原有的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_settings
是drf
默认配置。也可以在项目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'),
...
]
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_serializer
在get_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