Django 之restfromwork 源码分析之--视图组件

restframework 源码分析以及使用

mixins 中的五种类方法

from rest_framework import mixins
# mixins 中一种有五种类
# 第一种:用户保存数据
class CreateModelMixin(object):
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        # 序列化的类的对象
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)  # 校验
        self.perform_create(serializer)  # 保存
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        serializer.save()  # 保存

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
# 第二种:用户取出多条数据
class ListModelMixin(object):
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        # 过滤相关
        queryset = self.filter_queryset(self.get_queryset())
        # 分页相关
        page = self.paginate_queryset(queryset)
        if page is not None:
            # 序列化多条数据
            serializer = self.get_serializer(page, many=True)
            # 返回分页相关序列化对象的data
            return self.get_paginated_response(serializer.data)
        # 正常序列化
        serializer = self.get_serializer(queryset, many=True)
        # 正常返回
        return Response(serializer.data)
'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'
# 第三种:用于取出单个数据
class RetrieveModelMixin(object):
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
# 第四种:用户修改更新数据
class UpdateModelMixin(object):
    """
    Update a model instance.
    """
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
# 第五种: 用于删除数据
class DestroyModelMixin(object):
    """
    Destroy a model instance.
    """
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()

GenericAPIView类源码

from rest_framework.generics import 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__
        )
        # 这里的 self.queryset 根据 调用的时候 传值的querset来的
        queryset = self.queryset
        if isinstance(queryset, QuerySet):
            # Ensure queryset is re-evaluated on each request.
            queryset = queryset.all()
        return queryset  # 返回的 Querset对象

    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.
        """
        # 通过调用 get_serializer_class() 获取 序列化类
        serializer_class = self.get_serializer_class()
        kwargs['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)

视图类的四种方法

路由(前三种写法)

    url(r'^books/$',views.BooksView.as_view()),
    url(r'^books/(?P<pk>\d+)$',views.BookDetailView.as_view())
  • 基本写法(略)
  • 第二种写法
    from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, \ ListModelMixin, RetrieveModelMixin
    
    from rest_framework.generics import GenericAPIView
    from app01 import myser
    from app01 import models
    
    class BooksView(CreateModelMixin, ListModelMixin, GenericAPIView):
        queryset = models.Book.objects.all()
        serializer_class = myser.BookSerializer
    
        def post(self, request, *args, **kwargs):
            print(request.data)
            return self.create(request, *args, **kwargs)
    
        # 返回多条数据
        def get(self, request, *args, **kwargs):
            return self.list(request, *args, **kwargs)
    
    class BookDetailView(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView):
        queryset = models.Book.objects.all()
        serializer_class = myser.BookSerializer
    
        # 返回单条数据
        def get(self, request, *args, **kwargs):
            return self.retrieve(request, *args, **kwargs)
    
        # 修改数据
        def put(self, request, *args, **kwargs):
            return self.update(request, *args, **kwargs)
    
        # 删除数据
        def delete(self, request, *args, **kwargs):
            return self.destroy(request, *args, **kwargs)
  • 第三种写法
    class BooksView(ListCreateAPIView):
      queryset = models.Publish.objects.all()
      serializer_class = PublishSerializers
    
    class BookDetailView(RetrieveUpdateDestroyAPIView):
      queryset = models.Publish.objects.all()
      serializer_class = PublishSerializers
  • 第四种写法(两个视图类合成一个)

    路由

     url(r'^publish/$', views.PublishView.as_view({'get':'list','post':'create'})),
     url(r'^publish/(P<pk>\d+)/$',views.PublishView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
    from rest_framework.viewsets import ModelViewSet
    class PublishView(ModelViewSet):
      queryset=models.Publish.objects.all()
      serializer_class=PublishSerializers
    #  ViewSetMixin重写了as_view方法,路由配置就改了,可以写成映射的形式{get:get_one}
    #  as_view方法内部执行效果
    #   通过反射的取值跟赋值,完成映射,根据请求方式执行对应的方法(比如:get请求执行get_one方法,在路由中配置{get:getone})

    ?

原文地址:https://www.cnblogs.com/qianzhengkai/p/11135416.html

时间: 2024-10-29 16:46:35

Django 之restfromwork 源码分析之--视图组件的相关文章

Django搭建及源码分析(三)---+uWSGI+nginx

每个框架或者应用都是为了解决某些问题才出现旦生的,没有一个事物是可以解决所有问题的.如果觉得某个框架或者应用使用很不方便,那么很有可能就是你没有将其使用到正确的地方,没有按开发者的设计初衷来使用它,当你将一个框架的优势使用到极致时一定是非常舒服和顺手的一件事.但同时也有可能衍生另一个问题,这个框架只解决了你的问题一,没有解决问题二.三等等,因此,就出现了多个框架/应用相结合的情况.比如Django + uWSGI + nginx. 本人初学python,找了一些实例进行了一些操作,以下纯属目前的

Django如何启动源码分析

Django如何启动源码分析 启动 我们启动Django是通过python manage.py runsever的命令 解决 这句话就是执行manage.py文件,并在命令行发送一个runsever字符串 解析manage.py #!/usr/bin/env python import os import sys if __name__ == "__main__": #os.environ.setdefault 方法可以修改系统环境变量,但是只能os.environ 只能影响到当前运行

Django 之restfromwork 源码---APIView 分析

Django 之 djangorestframework的APIView分析 APIView 类中的as_view() 方法 首先 我们从视图函数入手,在urls.py 中的 URLconfig中添加一条路由 url(r'^books/',views.Book.as_view()), 此时,我们的BookView已经不是继承自django.views中View了,而是restframework.views中的APIView from django.shortcuts import render,

Django Rest Framework源码剖析(八)-----视图与路由

一.简介 django rest framework 给我们带来了很多组件,除了认证.权限.序列化...其中一个重要组件就是视图,一般视图是和路由配合使用,这种方式给我们提供了更灵活的使用方法,对于使用者而言不同的视图具有不同的功能,这样我们可以根据需求定制自己视图.以下是官网传送门:http://www.django-rest-framework.org/api-guide/views/ 在之前的文章中,由于参杂了权限.认证等(如果不了解请看博客的以前的文章),但在本章中基本可以不使用,所进使

django的RBAC认证z;自定义auth_user表;认证组件权限组件源码分析;认证组件;权限组件

一 RBAC 1.RBAC:全称(Role-Based Access Control):指的是基于用户权限访问控制的认证. 2.Django框架采用的是RBAC认证规则,RBAC认证规则通常会分为:三表规则,五表规则:Django采用的是六表规则. # 三表:用户表.角色表.权限表# 五表:用户表.角色表.权限表.用户角色关系表.角色权限关系表# 六表:用户表.角色表.权限表.用户角色关系表.角色权限关系表.用户权限关系表 3.在Django中六表之间是都是多对多的关系,可通过下面字段跨表访问

Django rest framework源码分析(一) 认证

一.基础 最近正好有机会去写一些可视化的东西,就想着前后端分离,想使用django rest framework写一些,顺便复习一下django rest framework的知识,只是顺便哦,好吧.我承认我是故意的,因为我始终觉得,如果好的技术服务于企业,顺便的提高一下自己.大家都很开心不是不.再次强调一下,真的只是顺便. 安装吧 pip install djangorestframework 1.2.需要先了解的一些知识 理解下面两个知识点非常重要,django-rest-framework

Django框架 --CBV源码分析、restful规范、restframework框架

一.CBV源码分析 1.url层的使用CBV from app01 import views url(r'book/',views.Book.as_view()) 2.as_view方法 as_view是一个类方法,实际上是一个闭包函数(内层函数包含对外层作用域的使用) 请求来了以后,调用as_view方法,调用函数中的view方法,view方法是调用了dispatch方法 @classonlymethod def as_view(cls, **initkwargs): def view(req

django中CBV源码分析

前言:Django的视图处理方式有两种: FBV(function base views) 是在视图里基于函数形式处理请求. CBV(class base views)是在视图里基于类的形式处理请求. Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承.封装.多态).所以Django在后来加入了Class-Based-View.可以让我们用类写View.这样做的优点主要下面两种: 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承) 可以

Django搭建及源码分析(二)

本节从由Django生成的manage.py开始,分析Django源码.python版本2.6,Django版本1.6.11. manage.py代码很简单. #!/usr/bin/env python import os import sys if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MyDjProj.settings") from d