您的位置:首页 > 编程语言 > Go语言

Django(55)GenericAPIView源码分析

2021-06-09 17:13 991 查看

源码分析

GenericAPIView
继承自
APIView
,也就是在
APIView
基础上再做了一层封装,源码如下:

class GenericAPIView(views.APIView):
queryset = None
serializer_class = None

lookup_field = 'pk'
lookup_url_kwarg = None

filter_backends = api_settings.DEFAULT_FILTER_BACKENDS

pagination_class = api_settings.DEFAULT_PAGINATION_CLASS

def get_queryset(self):
assert self.queryset is not None, (
"'%s' should either include a `queryset` attribute, "
"or override the `get_queryset()` method."
% self.__class__.__name__
)

queryset = self.queryset
if isinstance(queryset, QuerySet):
queryset = queryset.all()
return queryset

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

def get_serializer(self, *args, **kwargs):
serializer_class = self.get_serializer_class()
kwargs.setdefault('context', self.get_serializer_context())
return serializer_class(*args, **kwargs)
def get_serializer_class(self):
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)

return self.serializer_class
def get_serializer_context(self):
return {
'request': self.request,
'format': self.format_kwarg,
'view': self
}
def filter_queryset(self, queryset):
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
@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 paginate_queryset(self, queryset):
if self.paginator is None:
return None
return self.paginator.paginate_queryset(queryset, self.request, view=self)

def get_paginated_response(self, data):
assert self.paginator is not None
return self.paginator.get_paginated_response(data)

我们可以看到

GenericAPIView
中定义了6个类属性和8个方法,接下来一个个分析  

类属性

  • queryset = None
  • serializer_class = None
  • lookup_field = 'pk'
  • lookup_url_kwarg = None
  • filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
  • pagination_class = api_settings.DEFAULT_PAGINATION_CLASS  

queryset

  

queryset
是用来控制视图返回给前端的数据。如果没什么逻辑,可以直接写在视图的类属性中,如果逻辑比较复杂,也可以重写
get_queryset方法用来返回一个
queryset
对象。如果重写了
get_queryset
,那么以后获取
queryset
的时候就需要通过调用
get_queryset
方法。因为
queryset` 这个属性只会调用一次,以后所有的请求都是使用他的缓存。  

serializer_class

  

serializer_class
用来验证和序列化数据的。也是可以通过直接设置这个属性,也可以通过重写
get_serializer_class
来实现。  

lookup_field

在检索的时候,根据什么参数进行检索。默认是

pk
,也就是主键。  

lookup_url_kwarg

在检索的

url
中的参数名称。默认没有设置,跟
lookup_field
保持一致。  

filter_backends

用于过滤查询集的过滤器后端类的列表。默认值与

DEFAULT_FILTER_BACKENDS
设置的值相同。  

pagination_class

当分页列出结果时应使用的分页类。默认值与

DEFAULT_PAGINATION_CLASS
设置的值相同,即
'rest_framework.pagination.PageNumberPagination'
。  

方法

  • get_queryset
  • get_object
  • get_serializer
  • get_serializer_class
  • get_serializer_context
  • filter_queryset  

get_queryset

def get_queryset(self):
# 断言queryset是否不为None
assert self.queryset is not None, (
"'%s' should either include a `queryset` attribute, "
"or override the `get_queryset()` method."
% self.__class__.__name__
)

# 定义queryset属性,获取父类的queryset,如果父类没有定义类属性`queryset`,那么默认值就是None,就会报上面断言的错误
queryset = self.queryset
# 如果queryset是QuerySet对象,那么返回全部内容
if isinstance(queryset, QuerySet):
queryset = queryset.all()
# 如果不是queryset,那么直接返回
return queryset

get_queryset
默认是返回数据库全部数据,如果想返回其他数据,需要自定义  

get_object

def get_object(self):
queryset = self.filter_queryset(self.get_queryset())

# 查找过滤的条件,默认是pk
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

该方法是用于在数据检索(通过pk查找)的时候,返回一条数据的。  

get_serializer

def get_serializer(self, *args, **kwargs):
serializer_class = self.get_serializer_class()
kwargs.setdefault('context', self.get_serializer_context())
return serializer_class(*args, **kwargs)

返回应该用于验证和反序列化输入以及序列化输出的序列化器实例  

get_serializer_class

def get_serializer_class(self):
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)

return self.serializer_class

返回用于序列化的类。默认使用

self.serializer_class
。如果您需要根据传入请求提供不同的序列化,您可能需要重写它。  

get_serializer_context

def get_serializer_context(self):
return {
'request': self.request,
'format': self.format_kwarg,
'view': self
}

提供给序列化的额外上下文。  

filter_queryset

def filter_queryset(self, queryset):
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset

给定一个查询集,使用正在使用的过滤器对其进行过滤。您不太可能想要覆盖此方法,但如果您想将配置的过滤后端应用到默认查询集,您可能需要从列表视图或自定义

get_object
方法中调用它。  

实战案例

class StudentsGenericView(GenericAPIView):
queryset = Student.objects.all()  # 定义了类属性queryset,告诉视图要针对哪个模型做处理
serializer_class = StudentModelSerializer  # 定义类属性serlializer_class,告诉视图你的序列化的类是什么
def get(self, request, *args, **kwargs):
pk = kwargs.get("pk")
if pk:
many = False
query = self.get_object()  # 通过pk检索数据,返回一条数据
else:
many = True
query = self.get_queryset()  # 返回动态的数据集,默认返回全部
serializer = self.get_serializer(query, many=many)  # 如果数据对象是queryset对象,many需要为True
return APIResponse(results=serializer.data)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: