一、GenericAPIView源码解析
GenericAPIView继承自 APIView,也就是在 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
1、queryset
queryset是用来控制视图返回给前端的数据。如果没什么逻辑,可以直接写在视图的类属性中,如果逻辑比较复杂,也可以重写get_queryset方法用来返回一个queryset对象。如果重写了get_queryset,那么以后获取queryset的时候就需要通过调用get_queryset方法。因为queryset` 这个属性只会调用一次,以后所有的请求都是使用他的缓存。
2、serializer_class
serializer_class用来验证和序列化、反序列化数据的。也是可以通过直接设置这个属性,也可以通过重写get_serializer_class来实现。
3、lookup_field
在检索的时候,根据什么参数进行检索。默认是pk,也就是主键。
4、lookup_url_kwarg
在检索的url中的参数名称。默认没有设置,跟lookup_field保持一致。
5、filter_backends
用于过滤查询集的过滤器后端类的列表。默认值与DEFAULT_FILTER_BACKENDS 设置的值相同。
6、pagination_class
当分页列出结果时应使用的分页类。默认值与 DEFAULT_PAGINATION_CLASS 设置的值相同,即 ‘rest_framework.pagination.PageNumberPagination’。
方法
get_object()
get_queryset()
get_serializer()
get_serializer_class()
get_serializer_context()
paginate_queryset()
filter_queryset()
1、get_queryset()
get_queryset默认是返回数据库全部数据,如果想返回其他数据,需要自定义
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
2、get_object()
该方法是用于在数据检索(通过pk查找)的时候,返回一条数据的。
不需要重写get_object(),直接调用
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
3、get_serializer()
返回应该用于验证和反序列化输入以及序列化输出的序列化器实例
不需要重写get_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.setdefault('context', self.get_serializer_context())
return serializer_class(*args, **kwargs)
4、get_serializer_class()
返回用于序列化的类。默认使用 self.serializer_class。如果您需要根据传入请求提供不同的序列化,您可能需要重写它。
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
5、filter_queryset()
默认不需要过滤,如果需要过滤需要重写filter_queryset()方法
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
6、paginator()
a、paginator()方法让装饰器@property进行修饰,表示将方法暴露出去变成了属性
b、判断类属性中是否包含pagination_class方法,如果存在pagination_class,则变为pagination_class()方法并且赋值给self._paginator,返回self._paginator
@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
7、paginate_queryset()
a、默认不需要分页,如果需要分页需要重写paginate_queryset()方法
b、如果self.paginator 为 None,不需要进行过滤,否则需要通过self.paginator.paginate_queryset()方法进行过滤
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)
我的视图
重写了get_queryset()方法和get_serializer_class()方法
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from app2.models import NewsChannel
from app2.serializers1 import NewsChannelSerializer,NewsChannel1Serializer
class ChannelsAPIView(GenericAPIView):
queryset = NewsChannel.objects.all()
serializer_class = NewsChannelSerializer
def get_queryset(self):
return NewsChannel.objects.filter(id__exact=2)
def get_serializer_class(self):
return NewsChannel1Serializer
def get(self, request,*args,**kwargs):
queryset=self.get_queryset()
serializer=self.get_serializer(instance=queryset,many=True)
return Response(serializer.data)
def post(self,request):
serializer=self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)