Django(55)GenericAPIView源码分析

摘要:
如果没什么逻辑,可以直接写在视图的类属性中,如果逻辑比较复杂,也可以重写get_queryset方法用来返回一个queryset对象。因为queryset这个属性只会调用一次,以后所有的请求都是使用他的缓存。serializer_classserializer_class用来验证和序列化数据的。也是可以通过直接设置这个属性,也可以通过重写get_serializer_class来实现。lookup_url_kwarg在检索的url中的参数名称。默认没有设置,跟lookup_field保持一致。filter_backends用于过滤查询集的过滤器后端类的列表。默认值与DEFAULT_FILTER_BACKENDS设置的值相同。pagination_class当分页列出结果时应使用的分页类。
源码分析

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)

免责声明:文章转载自《Django(55)GenericAPIView源码分析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Hadoop2.7.3集群安装scala-2.12.8 和spark2.7OnPaint和OnDraw的区别下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ubuntu 16.04 安装nodejs

Ubuntu 上安装 Node.js Node.js 源码安装 以下部分我们将介绍在Ubuntu Linux下安装 Node.js 。 其他的Linux系统,如Centos等类似如下安装步骤。 在 Github 上获取 Node.js 源码: $ sudo git clone https://github.com/nodejs/node.git Clon...

Django框架详细介绍---请求流程

Django请求流程图 1.客户端发送请求 2.wsgiref是Django封装的套接字,它将客户端发送过来的请求(请求头、请求体封装成request)    1)解析请求数据   2)封装响应数据  3.中间件,进项身份验证等 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddlewa...

[转]找到运行的Ubuntu版本对应的内核源码

原文:找到运行的Ubuntu版本对应的内核源码 ---------------------------------------------------------------------- 本文主要讲述,如何根据当前运行的Ubuntu版本,找到对应的内核源码。 首先,按照下面链接里的内容,下载对应的内核源码仓库。 https://wiki.ubuntu.c...

django:开发一个下载图片的接口

html页面如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form a...

Django的View(视图)

Django的View(视图) 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。 响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。 无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你当前项目目录下面。除此之外没有更多的要求了——可以说“...

Django模型Model之数据控制详解

模型是MVC架构中访问数据的模块,Django的模型对各种数据库提供了很好的支持。这里以MySQL为例介绍Django的模型。 使用模型 启用数据库支持 在项目的 settings.py 文件中找到 DATABASES 配置项, 根据数据库配置信息: DATABASES = { 'default': { 'ENGINE': 'dj...