APIView 官网
- 基础
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework.generics import ListCreateAPIView
from rest_framework.generics import get_object_or_404
-
参数
http_method_names = ['post','get']
设置允许的请求方法self.kwargs['key']
获取url里面的参数
-
方法
dispatch(self, request, *args, **kwargs)
def dispatch(self, request, *args, **kwargs): try: except Exception as exc: response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs) return self.response
get_permissions(self)
: 返回所有的permission
return [permission() for permission in self.permission_classes]
handle_exception
处理各种APIException
get_object_or_404
from django.http import Http404
def get_object_or_404(queryset, *filter_args, **filter_kwargs):
"""
Same as Django's standard shortcut, but make sure to also raise 404
if the filter_kwargs don't match the required types.
"""
try:
return _get_object_or_404(queryset, *filter_args, **filter_kwargs)
except (TypeError, ValueError, ValidationError):
raise Http404
GenericAPIView.get_queryset
可能你需要根据请求来过滤
def get_queryset(self):
if self.request.user.is_superuser:
return self.queryset.all()
else:
return self.queryset.filter(user=self.request.user)
GenericAPIView.get_serializer_class
可能你要根据request调用不同的序列化类
def get_serializer_class(self):
if self.request.method == "GET":
return serializers.VoteListSerializer
DestroyAPIView.perform_destroy
你可能要假删除只修改状态
def perform_destroy(self, instance):
# instance.delete()
instance.status = 'delete'
instance.save()
GenericAPIView.get_serializer
可能你要根据这个instance的user是不是request.user来做不同的序列化类
def get_serializer(self, *args, **kwargs):
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context() # 一般来说这个kwargs是空的
return serializer_class(*args, **kwargs)
GenericAPIView.get_serializer_context
可能你要传递额外的数据进去,最常见的就是request.user了,不过这个已经有了
def get_serializer_context(self):
return {
"request": self.request,
"format": self.format_kwarg, # 尚且不清楚他的用处
"view": self # 这个有用,可以在ClassView里面加入类似 level_require 或者 permission_level 然后在序列化类里面做判断
}
- 代码
def get_serializer(instance, *args, **kwargs):
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
def get_serializer_class(self):
return self.serializer_class
def get_serializer_context(self):
return {
'request': self.request,
'format': self.format_kwarg,
'view': self
}
def get_object(self):
...
self.check_object_permissions(self.request, obj)
get_serializer(self, instance=None, data=None, many=False, partial=False)
返回serializer。
def get_serializer(self, *args, **kwargs):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
"""
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
filter_queryset(self, queryset)
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
- GET请求顺序
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
def filter_queryset(self, queryset):
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
def paginate_queryset(queryset):
if self.paginator is None:
return None
else:
return self.paginator.paginate_queryset(queryset, self.request, view=self)
@property
def paginator(self):
if not hasattr(self, '_paginator'):
if self.pagination_class is None:
self._paginator = None
else:
self._paginator = self.pagination_class()
return self._paginator
def get_queryset(self):
return self.queryset
def get_paginated_response(self, data):
assert self.paginator is not None
return self.paginator.get_paginated_response(data)
def paginator.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)
]))
self._paginator = self.pagination_class()
self._paginator.paginate_queryset(queryset, self.request, view=self)
def paginate_queryset(self, queryset, request, view=None):
page_size = self.get_page_size(request)
def get_page_size(self, request):
if self.page_size_query_param:
try:
return _positive_int(
request.query_params[self.page_size_query_param],
strict=True,
cutoff=self.max_page_size
)
except (KeyError, ValueError):
pass
return self.page_size
- POST请求顺序
ListCreateAPIView.post # 没有什么操作 CreateModelMixin.create(self, request, *args, **kwargs) # 验证数据 serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) 1. CreateModelMixin.perform_create # serializer.save() 如果要save后进行其他操作,修改这个函数
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance) # 注意,这里的get_serializer里面没有加入kwargs参数,不然会因为有id这个参数而导致报错
return Response(serializer.data)
def get_serializer(self, *args, **kwargs)
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
assert lookup_url_kwarg in self.kwargs, (
'Expected view %s to be called with a URL keyword argument '
'named "%s". Fix your URL conf, or set the `.lookup_field` '
'attribute on the view correctly.' %
(self.__class__.__name__, lookup_url_kwarg)
)
filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
obj = get_object_or_404(queryset, **filter_kwargs)
self.check_object_permissions(self.request, obj)
return obj
self.delete(self, request, *args, **kwargs)
self.destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
DestroyModelMixin.perform_destroy(instance):
instance.delete()
def patch(self, request, *args, **kwargs)
return self.partial_update(request, *args, **kwargs)
def partial_update(self, request, *args, **kwargs)
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
self.update(request, *args, **kwargs)
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response(serializer.data)
self.perform_update(serializer)
serializer.save()