rest_framework listview的执行顺序
class CourseListAPIView(ResponseMixin, generics.ListAPIView)
2)ListAPIView
提供 get 方法,展示对象列表信息
继承自:GenericAPIView、ListModelMixin
GenericAPIView,提供了get_queryset,filter_queryset, paginate_queryset等方法便于列表视图与详情信息视图的开发。
ListModelMixin,列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码。
执行顺序
- 浏览器对路由进行访问
- 执行CourseListAPIView.as_view()方法,DRF的APIVIEW的as_view,以及dispatch对django的request进行再次封装,并进行认证,频率,权限认证
listview的执行顺序
class CourseListAPIView(ResponseMixin, generics.ListAPIView):
3.get请求过来,先执行get方法>>>>执行的是ListAPIView的get方法
class ListAPIView(mixins.ListModelMixin,GenericAPIView):
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
4.执行list方法>>>>ListModelMixin的list方法
class ListModelMixin(object):
def list(self, request, *args, **kwargs):
self.object_list = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(self.object_list)
if page is not None:
serializer = self.get_pagination_serializer(page)
else:
serializer = self.get_serializer(self.object_list, many=True)
return Response(serializer.data)
5.执行get_queryset方法>>>>GenericAPIView(views.APIView)的get_queryset方法
#可以通过重写get_querset方法实现过滤
def get_queryset(self):
if self.queryset is not None:
return self.queryset._clone()
①._clone方法
就是复制对象
6. 执行filter_queryset方法>>>>GenericAPIView(views.APIView)的filter_queryset方法
def filter_queryset(self, queryset):
for backend in self.get_filter_backends():
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
①get_filter_backends方法
def get_filter_backends(self):
if self.filter_backends is None:
filter_backends = []
else:
filter_backends = list(self.filter_backends)
if not filter_backends and self.filter_backend:
warnings.warn(
'The `filter_backend` attribute and `FILTER_BACKEND` setting '
'are deprecated in favor of a `filter_backends` '
'attribute and `DEFAULT_FILTER_BACKENDS` setting, that take '
'a *list* of filter backend classes.',
DeprecationWarning, stacklevel=2
)
filter_backends = [self.filter_backend]
return filter_backends
7.执行page_queryset方法>>>>GenericAPIView(views.APIView)的page_queryset方法
def paginate_queryset(self, queryset, page_size=None):
deprecated_style = False
if page_size is not None:
warnings.warn('The `page_size` parameter to `paginate_queryset()` '
'is deprecated. '
'Note that the return style of this method is also '
'changed, and will simply return a page object '
'when called without a `page_size` argument.',
DeprecationWarning, stacklevel=2)
deprecated_style = True
else:
page_size = self.get_paginate_by()
if not page_size:
return None
if not self.allow_empty:
warnings.warn(
'The `allow_empty` parameter is deprecated. '
'To use `allow_empty=False` style behavior, You should override '
'`get_queryset()` and explicitly raise a 404 on empty querysets.',
DeprecationWarning, stacklevel=2
)
paginator = self.paginator_class(queryset, page_size,
allow_empty_first_page=self.allow_empty)
page_kwarg = self.kwargs.get(self.page_kwarg)
page_query_param = self.request.QUERY_PARAMS.get(self.page_kwarg)
page = page_kwarg or page_query_param or 1
try:
page_number = paginator.validate_number(page)
except InvalidPage:
if page == 'last':
page_number = paginator.num_pages
else:
raise Http404(_("Page is not 'last', nor can it be converted to an int."))
try:
page = paginator.page(page_number)
except InvalidPage as exc:
error_format = _('Invalid page (%(page_number)s): %(message)s')
raise Http404(error_format % {
'page_number': page_number,
'message': str(exc)
})
if deprecated_style:
return (paginator, page, page.object_list, page.has_other_pages())
return page
①get_paginate_by
def get_paginate_by(self, queryset=None):
if queryset is not None:
warnings.warn('The `queryset` parameter to `get_paginate_by()` '
'is deprecated.',
DeprecationWarning, stacklevel=2)
if self.paginate_by_param:
try:
return strict_positive_int(
self.request.QUERY_PARAMS[self.paginate_by_param],
cutoff=self.max_paginate_by
)
except (KeyError, ValueError):
pass
return self.paginate_by
paginate_by = api_settings.PAGINATE_BY
8.分页的话,执行get_pagination_serializer >>>>GenericAPIView(views.APIView)的 get_pagination_serializer
def get_pagination_serializer(self, page):
class SerializerClass(self.pagination_serializer_class):
class Meta:
object_serializer_class = self.get_serializer_class()
pagination_serializer_class = SerializerClass
context = self.get_serializer_context()
return pagination_serializer_class(instance=page, context=context)
①get_serializer_context
提供给序列化器额外的参数
def get_serializer_context(self):
return {
'request': self.request,
'format': self.format_kwarg,
'view': self
}
9.不分页的话 get_serializer
def get_serializer(self, instance=None, data=None, files=None, many=False,
partial=False, allow_add_remove=False):
serializer_class = self.get_serializer_class()
context = self.get_serializer_context()
return serializer_class(instance, data=data, files=files,
many=many, partial=partial,
allow_add_remove=allow_add_remove,
context=context)
实践
from courseact.rest.mixin import ResponseMixin
from rest_framework import generics
from courseact.rest.pagination import CommonPaginationSerializer
class ClassListAPIView(ResponseMixin, generics.ListAPIView):
pagination_serializer_class = CommonPaginationSerializer
queryset = Klass.objects.all()
serializer_class = KlassListSerializer
③def get_serializer_context(self):
print("3")
user = self.request.user
return {'user': user}#user = self.context['user']后续序列化器使用
①def get_queryset(self):#获取对象列表,可以进行分组,排序操作
print("1")
return self.queryset
②def filter_queryset(self, queryset):#对对象列表进行筛选
print("2")
data = self.request.GET.dict()
center = get_center_for_user(self.request.user)
queryset = queryset.filter(center=center, academic_year=int(data.get("academic_year")))
return queryset