Django源码解析之视图

1 认证源码分析

资料链接:http://www.sohu.com/a/222215490_729271

2 处理请求wsgi分析与视图View

资料链接:https://blog.csdn.net/qq_33339479/article/details/78879571

  • 基类View的简要分析
    在url中,调用View类中的as_view方法,此时就会调用as_view中的view方法,该方法最终调用View类的self.dispatch,通过筛选后调用相应的handler处理。 handler对应的就是get/post/put/delete等具体的方法。所以在继承View的class中,只要重新定义了get/post/put/delete方法,URL调用时会自动进入该类相应的方法中。

3 视图类的对比分析

资料链接:https://blog.csdn.net/odyssues_lee/article/details/80895207

3.1 APIView与View的不同(APIView继承与View)
from django.views import View
from rest_framework.views import APIView
  • (1) View来自django.views,APIView来自rest_framework.views,APIView比View有更多的封装,且APIView继承于View。
  • (2) APIView传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
  • (3)视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
  • (4) 任何APIException异常都会被捕获到,并且处理成合适的响应信息;
  • (5)在进行dispatch()分发前,多了对请求进行身份认证、权限检查、流量控制。对应的源码如下:
 # Ensure that the incoming request is permitted
        self.perform_authentication(request)
        self.check_permissions(request)
        self.check_throttles(request)
  • (6)获取参数的区别
    继承View的类:
    get 获取参数:params = req.GET
    post 获取参数:params = req.POST
    put/delete获取参数:params = QueryDict(req.body)
from django.http import QueryDict

继承APIView的类:
get 获取参数:params = req.query_params
post/put/delete获取参数:params = req.data

APIView支持定义的属性:

  • authentication_classes 列表或元祖,身份认证类
  • permissoin_classes 列表或元祖,权限检查类
  • throttle_classes 列表或元祖,流量控制类
3.2 GenericAPIView(继承自APIView)

GenericAPIView较APIView有了更多的封装:增加了对于列表视图和详情视图可能用到的通用支持方法。通常使用时,可搭配一个或多个Mixin扩展类。

  • 多了属性:
    queryset 列表视图的查询集
    serializer_class 视图使用的序列化器
    pagination_class 分页控制类
    filter_backends 过滤控制后端
    lookup_field 查询单一数据库对象时使用的条件字段(lookup_field的值为数据库表里的字段),默认为'pk'
    lookup_url_kwarg 查询单一数据时URL中的参数关键字名称,默认与look_field相同
# lookup_field与lookup_url_kwarg的使用举例
url(r"^config/(?P<id>/$", views.TestView.as_view()),

class TestView(mixins.UpdateModelMixin,
               mixins.DestroyModelMixin,
               generics.GenericAPIView):
    """改配置"""
    queryset = Config.objects.all()
    lookup_field = ('uuid')
    lookup_url_kwarg = ('id')

    def put(self, request, *args, **kwargs):     
            instance = self.get_object()
    # get_object会根据lookup_field 和lookup_url_kwarg 的值来过滤获取单个对象,过滤方法相当于:filter(uuid=id参数的值)。
    # uuid为数据库表里的字段,id为参数中的关键字,即获取的是字段uuid=id参数的值的对象。通常lookup_url_kwarg 默认就是lookup_field 的值,代码中只需要设置lookup_field ,只有两者值不相同时才需要分别单独设置。
  • 多提供的方法:
    get_queryset(self):返回视图使用的查询集,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写,例如:
def get_queryset(self):
    user = self.request.user
    return user.accounts.all()

get_serializer_class(self)返回序列化器类,默认返回serializer_class,可以重写,例如:

def get_serializer_class(self):
    if self.request.user.is_staff:
        return FullAccountSerializer
    return BasicAccountSerializer

get_serializer(self, args, *kwargs)返回序列化器对象,被其他视图或扩展类使用,如果我们在视图中想要获取序列化器对象,可以直接调用此方法。

get_object(self):返回详情视图所需的模型类数据对象,默认使用lookup_field参数来过滤queryset。 在试图中可以调用该方法获取详情信息的模型类对象。
若详情访问的模型类对象不存在,会返回404。

get_serializer_context:获取序列化的数据,定义了某种格式的字典

class BookDetailView(GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
 
    def get(self, request, pk):
        book = self.get_object()
        serializer = self.get_serializer(book)
        return Response(serializer.data)
3.3 配合使用的5个类扩展(from rest_framework import mixins)

宏观感受: mixins的这5个类扩展方法主要是对数据的增删改查进行封装.

  • ListModelMixin:提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码。该Mixin的list方法会对数据进行过滤和分页。

  • CreateModelMixin:提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码。在一些情境下,我们需要对里面的perform_create( )进行重写。例如:

def perform_create(self, serializer):
# 重写save的逻辑,除了serializer.save()外,还需要对course的收藏数fav_num加1
    instance = serializer.save()
    course = instance.course
    course.fav_num += 1
    course.save()
  • RetrieveModelMixin:提供retrieve(request, *args, **kwargs)方法,可以快速实现返回一个存在的数据对象。对retrieve这个方法的重写几率比较高,例如我们在增加点击数的时候,经常要对其进行一个重写。

  • UpdateModelMixin:提供update(request, *args, **kwargs)方法,可以快速实现更新一个存在的数据对象。同时也提供partial_update(request, *args, **kwargs)方法,可以实现局部更新。如果需要对更新这个逻辑进行自定义,那么需要重写perform_update( )方法,而尽量少去重写update( )

  • DestroyModelMixin:提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象。

3.4 子类视图

rest_framework.generics里面除了提供GenericAPIView以外,还有CreateAPIView/ListAPIView/RetrieveAPIView/DestroyAPIView/UpdateAPIView/ListCreateAPIView/RetrieveUpdateAPIView/RetrieveDestroyAPIView/RetrieveUpdateDestroyAPIView 9个子类视图,这些视图函数无非都是GenericAPIView与上面mixins的5个类扩展的各种组合.例如:

  • 1) CreateAPIView
    提供 post 方法,继承自: GenericAPIView、CreateModelMixin
  • 2)ListAPIView
    提供 get 方法,继承自:GenericAPIView、ListModelMixin
  • 3)RetireveAPIView
    提供 get 方法,继承自: GenericAPIView、RetrieveModelMixin
  • 4)DestoryAPIView
    提供 delete 方法,继承自:GenericAPIView、DestoryModelMixin
  • 5)UpdateAPIView
    提供 put 和 patch 方法,继承自:GenericAPIView、UpdateModelMixin
  • 6)RetrieveUpdateAPIView
    提供 get、put、patch方法,继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
  • 7)RetrieveUpdateDestoryAPIView
    提供 get、put、patch、delete方法,继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
3.5 视图类的使用举例

参考资料1:https://blog.csdn.net/u013210620/article/details/79869661

BookView是对book表的所有记录查询、增加某些数据记录
BookViewDetail是对book表单条数据的查询、修改、删除

from rest_framework import mixins
from rest_framework import generics

#ListModelMixin适用于查询数据列表
class BookView(mixins.ListModelMixin,
               mixins.CreateModelMixin,
               generics.GenericAPIView):

    queryset = Book.objects.all()
    serializer_class = BookSerializers

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

/*
RetrieveModelMixin 适用于查询单个对象的详情数据,
UpdateModelMixin 适用于更新单条数据
DestroyModelMixin 删除单条数据
*/
class BookViewDetail(
    mixins.RetrieveModelMixin,
    mixins.DestroyModelMixin,
    mixins.UpdateModelMixin,
    generics.GenericAPIView
):
    queryset = Book.objects.all()
    serializer_class = BookSerializers

    def get(self,request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def delete(self,request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

    def put(self,request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
3.6 viewSet视图

django中除了上面提到的GenericAPIView等视图外,还有一类很重要的视图函数--ViewSet类视图,viewsets.py文件中提供的.
参考资料:https://blog.csdn.net/u013210620/article/details/79879611
https://www.jianshu.com/p/2c3fc8060a63
几种ViewSet类的关系图:

  • 基类ViewSetMixin中重写了as_view()方法,方便了对API路由的管理.
3.6.1 viewSet类视图与url的绑定方法
  • 方法一:action中绑定
    ViewSetMixin的as_view()方法中提供了actions参数,可以利用action参数将get/post/put/delete等方法与list/create/update/destroy等动作关联起来.使用举例:
urlpatterns = [
    url(r"bookset/$",BookSet.as_view({'get': 'list', 'post': 'create'})),
    url(r"bookset/(?P<pk>\d+)/$",BookSet.as_view({'get': 'retrieve', 'put': 'update','delete': 'destroy'})),
]
  • 方法二:action中绑定方式二
    这种方法的本质同方法一,只不过是将as_view的绑定过程抽出来了,例如:
book_list = BookSet.as_view({
    'get': 'list',
    'post': 'create'
})
book_detail = BookSet.as_view({
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
})

urlpatterns = [
    url(r'^bookset/$', book_list, name='book-list'),
    url(r'^bookset/(?P<pk>\d+)/$', book_detail, name='book-detail'),
]
  • 方法三:routers自动绑定
    使用举例:
from django.conf.urls import url,include
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'bookset', BookSet)

urlpatterns = [
    url(r'^', include(router.urls)),
]
备注:router的方式中虽然没有定义name参数,但router内部会自动生成,name的格式同方法二中name的格式.
3.7 @list_route和@detail_route的使用

list_route和detail_route装饰器是为了能在Viewset中自定义方法而提供的.两者的区别是list_route对应的detail=False,detail_route对应的detail=True,也就是list_route对应的是一般列表,而detail_route需要返回详情.

在DRF 3.10这个版本后使用 @action 代替了 @list_router和@detail_router。

@detail_route 相当于 @action(detail=True).
@list_route 相当于 @action(detail=False).

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容