一、GenericAPIView类源码
class GenericAPIView(views.APIView):
"""
Base class for all other generic views.
"""
# You'll need to either set these attributes,
# or override `get_queryset()`/`get_serializer_class()`.
# If you are overriding a view method, it is important that you call
# `get_queryset()` instead of accessing the `queryset` property directly,
# as `queryset` will get evaluated only once, and those results are cached
# for all subsequent requests.
queryset = None
serializer_class = None
# If you want to use object lookups other than pk, set 'lookup_field'.
# For more complex lookup requirements override `get_object()`.
lookup_field = 'pk'
lookup_url_kwarg = None
# The filter backend classes to use for queryset filtering
filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
# The style to use for queryset pagination.
pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
def get_queryset(self):
"""
Get the list of items for this view.
This must be an iterable, and may be a queryset.
Defaults to using `self.queryset`.
This method should always be used rather than accessing `self.queryset`
directly, as `self.queryset` gets evaluated only once, and those results
are cached for all subsequent requests.
You may want to override this if you need to provide different
querysets depending on the incoming request.
(Eg. return a list of items that is specific to the user)
"""
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):
# Ensure queryset is re-evaluated on each request.
queryset = queryset.all()
return queryset
def get_object(self):
"""
Returns the object the view is displaying.
You may want to override this if you need to provide non-standard
queryset lookups. Eg if objects are referenced using multiple
keyword arguments in the url conf.
"""
queryset = self.filter_queryset(self.get_queryset())
# Perform the lookup filtering.
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)
# May raise a permission denied
self.check_object_permissions(self.request, obj)
return obj
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.setdefault('context', self.get_serializer_context())
return serializer_class(*args, **kwargs)
def get_serializer_class(self):
"""
Return the class to use for the serializer.
Defaults to using `self.serializer_class`.
You may want to override this if you need to provide different
serializations depending on the incoming request.
(Eg. admins get full serialization, others get basic serialization)
"""
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):
"""
Extra context provided to the serializer class.
"""
return {
'request': self.request,
'format': self.format_kwarg,
'view': self
}
def filter_queryset(self, queryset):
"""
Given a queryset, filter it with whichever filter backend is in use.
You are unlikely to want to override this method, although you may need
to call it either from a list view, or from a custom `get_object`
method if you want to apply the configured filtering backend to the
default queryset.
"""
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
@property
def paginator(self):
"""
The paginator instance associated with the view, or `None`.
"""
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):
"""
Return a single page of results, or `None` if pagination is disabled.
"""
if self.paginator is None:
return None
return self.paginator.paginate_queryset(queryset, self.request, view=self)
def get_paginated_response(self, data):
"""
Return a paginated style `Response` object for the given output data.
"""
assert self.paginator is not None
return self.paginator.get_paginated_response(data)
二、GenericAPIView介绍
GenericAPIView 是 Django REST Framework(DRF)中的一个基础视图类,它为开发者提供了一些通用的功能和方法,用于快速构建 API 视图。
GenericAPIView 类是通过结合 APIView 和 GenericAPIViewMixin 类而来。它继承了 APIView 类,同时混入了 GenericAPIViewMixin 类中的方法和属性。
2.1 GenericAPIView 类的关键特点和常用方法:
2.1.1 提供常用的 HTTP 方法处理函数:
GenericAPIView 类提供了常见的 HTTP 方法处理函数,如
- get():处理 HTTP GET 请求;
- post():处理 HTTP POST 请求;
- put():处理 HTTP PUT 请求;
- patch():处理 HTTP PATCH 请求;
- delete():处理 HTTP DELETE 请求;
- head():处理 HTTP HEAD 请求;
- options():处理 HTTP OPTIONS 请求
可以通过重写这些方法来实现对不同 HTTP 方法的处理逻辑。
注意:
继承GenericAPIView 类,需要手动重写HTTP 方法处理函数
1、GenericAPIView 类提供了常见的 HTTP 方法处理函数,这些方法实际上是由 APIView 类来实现的
GenericAPIView 类继承了 APIView 类,通过混入一些 Mixin 类来扩展其功能。它并没有直接实现所有的 HTTP 方法处理函数,而是借用了 APIView 类中已经实现的相应方法。这些方法包括:
- get():处理 HTTP GET 请求;
- post():处理 HTTP POST 请求;
- put():处理 HTTP PUT 请求;
- patch():处理 HTTP PATCH 请求;
- delete():处理 HTTP DELETE 请求;
- head():处理 HTTP HEAD 请求;
- options():处理 HTTP OPTIONS 请求。
APIView 类是 DRF 中最基础的视图类,它定义了每个方法对应的默认行为,但这些默认行为通常需要根据具体情况进行自定义实现。因此,GenericAPIView 类作为 APIView 类的子类,提供了更加灵活和可定制的视图功能。
通过继承 GenericAPIView 类,并根据具体需求重写相关的方法,开发者可以很方便地实现自己的视图逻辑和业务处理。在实际使用中,我们一般会结合 GenericAPIView 类的 Mixin 类(如 ListAPIView、RetrieveAPIView 等)来进一步简化开发过程,以实现更具体的功能。
2、支持多种常用的数据操作:
GenericAPIView 类封装了常见的数据操作,包括获取查询集、进行过滤、排序、分页等操作。它提供了一些属性和方法,如 queryset、filter_queryset()、paginate_queryset() 等,通过它们可以轻松实现数据操作的逻辑。
3、内置了常见的 Mixin 类方法:
GenericAPIView 类内置了一些常用的 Mixin 类方法。
以下是 GenericAPIView 类内置的几个常用的 Mixin 类方法:
- ListAPIView: 这个 Mixin 类实现了处理 GET 请求返回列表数据的逻辑。它提供了默认的列表数据查询和序列化逻辑,你只需要在子类中指定查询集和序列化器即可。
- CreateAPIView: 这个 Mixin 类实现了处理 POST 请求创建资源的逻辑。它提供了默认的请求数据反序列化和保存逻辑,你只需要在子类中指定序列化器即可。
- RetrieveAPIView: 这个 Mixin 类实现了处理 GET 请求获取单个资源的逻辑。它提供了默认的资源查询和序列化逻辑,你只需要在子类中指定查询集和序列化器即可。
- UpdateAPIView: 这个 Mixin 类实现了处理 PUT/PATCH 请求更新资源的逻辑。它提供了默认的请求数据反序列化、资源查询和保存逻辑,你只需要在子类中指定查询集和序列化器即可。
- DestroyAPIView: 这个 Mixin 类实现了处理 DELETE 请求删除资源的逻辑。它提供了默认的资源查询和删除逻辑,你只需要在子类中指定查询集即可。
这些 Mixin 方法可与 GenericAPIView 类一起使用,以构建满足特定需求的视图类。你可以根据需要选择并组合这些 Mixin 类方法,以便在视图类中实现常见的 REST 功能。
例如,如果你想创建一个处理 GET 请求返回列表数据的视图类,你可以从 GenericAPIView 和 ListAPIView 派生一个新的子类,并在子类中指定查询集和序列化器。然后,视图类将自动提供列表数据的查询和序列化功能。
from rest_framework.generics import GenericAPIView, ListAPIView
from myapp.models import MyModel
from myapp.serializers import MyModelSerializer
class MyListView(GenericAPIView, ListAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
在上面的示例中,我们定义了一个名为 MyListView 的视图类,它继承自 GenericAPIView 和 ListAPIView。我们指定了查询集 (queryset) 和序列化器 (serializer_class),这样视图类就具备了处理 GET 请求返回列表数据的功能。
通过使用这些内置的 Mixin 类方法,可以更轻松地构建出符合需求的视图类,并减少重复代码的编写。
4、支持使用序列化器类:
GenericAPIView 类提供了 serializer_class 属性,用于指定使用的序列化器类。通过 get_serializer() 方法可以获取实例化后的序列化器对象,并在视图中使用它进行数据的序列化和反序列化操作。
5、简化了 API 视图开发:
借助 GenericAPIView 类和相关的 Mixin 类,可以大幅简化 API 视图的开发工作。它们提供了许多通用的方法和属性,减少了重复编写代码的工作量,提高了开发效率。
总而言之,GenericAPIView 类是 DRF 框架中一个非常有用的基础视图类,通过继承和结合相关的 Mixin 类,它提供了许多通用的功能和方法,简化了 API 视图的开发过程。开发者可以根据自己的需求,结合 GenericAPIView 类的特性,快速构建出符合 RESTful 设计风格的 API 视图。