侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Django CBV与FBV原理及实例详解

框架(架构)  /  管理员 发布于 7年前   147

一、FBV

FBV(function base views) 就是在视图里使用函数处理请求。

二、CBV

CBV(class base views) 就是在视图里使用类处理请求。

Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View。可以让我们用类写View。这样做的优点主要下面两种:

提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性
1、class-based views的使用

(1)写一个处理GET方法的view

用函数写的话如下所示:

from django.http import HttpResponsedef my_view(request):   if request.method == 'GET':      return HttpResponse('OK')

用class-based view写的话如下所示:

from django.http import HttpResponsefrom django.views import Viewclass MyView(View):   def get(self, request):      return HttpResponse('OK')

(2)用url请求分配配置

Django的url是将一个请求分配给可调用的函数的,而不是一个class。针对这个问题,class-based view提供了一个as_view()静态方法(也就是类方法),调用这个方法,会创建一个类的实例,然后通过实例调用dispatch()方法,dispatch()方法会根据request的method的不同调用相应的方法来处理request(如get() , post()等)。

到这里,这些方法和function-based view差不多了,要接收request,得到一个response返回。如果方法没有定义,会抛出HttpResponseNotAllowed异常。

在url中,写法如下:

# urls.pyfrom django.conf.urls import urlfrom myapp.views import MyViewurlpatterns = [   url(r'^index/$', MyView.as_view()),]

类的属性可以通过两种方法设置,第一种是常见的python的方法,可以被子类覆盖:

from django.http import HttpResponsefrom django.views import Viewclass GreetingView(View):  name = "yuan"  def get(self, request):     return HttpResponse(self.name)  # You can override that in a subclass  class MorningGreetingView(GreetingView):  name= "alex"

第二种方法,可以在url中指定类的属性:

在url中设置类的属性Python

urlpatterns = [  url(r'^index/$', GreetingView.as_view(name="egon")),]

2、使用Mixin

要理解django的class-based-view(以下简称cbv),首先要明白django引入cbv的目的是什么。在django1.3之前,generic view也就是所谓的通用视图,使用的是function-based-view(fbv),亦即基于函数的视图。有人认为fbv比cbv更pythonic,窃以为不然。python的一大重要的特性就是面向对象。

而cbv更能体现python的面向对象。cbv是通过class的方式来实现视图方法的。class相对于function,更能利用多态的特定,因此更容易从宏观层面上将项目内的比较通用的功能抽象出来。关于多态,不多解释,有兴趣的同学自己Google。总之可以理解为一个东西具有多种形态(的特性)。

cbv的实现原理通过看django的源码就很容易明白,大体就是由url路由到这个cbv之后,通过cbv内部的dispatch方法进行分发,将get请求分发给cbv.get方法处理,将post请求分发给cbv.post方法处理,其他方法类似。

怎么利用多态呢?cbv里引入了mixin的概念。Mixin就是写好了的一些基础类,然后通过不同的Mixin组合成为最终想要的类。

所以,理解cbv的基础是,理解Mixin。Django中使用Mixin来重用代码,一个View Class可以继承多个Mixin,但是只能继承一个View(包括View的子类),推荐把View写在最右边,多个Mixin写在左边。

三、CBV示例

1、CBV应用简单示例

########### urls.pyfrom django.contrib import adminfrom django.urls import pathfrom app01 import views urlpatterns = [  path('admin/', admin.site.urls),  path('login/', views.LoginView.as_view()),] ############views.pyfrom django.shortcuts import render, HttpResponsefrom django.views import Viewclass LoginView(View):  def get(self, request):    return render(request, "login.html")   def post(self, request):    return HttpResponse("post...")   def put(self, request):    pass

构建login.html页面:

<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <title>Title</title></head><body><form action="" method="post">  {% csrf_token %}  <input type="submit"></form></body></html>

注意:

(1)CBV的本质还是一个FBV

(2)url中设置类的属性Python:

path('login/', views.LoginView.as_view()),

用户访问login,views.LoginView.as_view()一定是一个函数名,不是函数调用。

(3)页面效果

 

点击提交post请求:

2、from django.views import View的源码查看

class View:  """  get:查 post:提交,添加 put:所有内容都更新  patch:只更新一部分  delete:删除  """  http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']  def __init__(self, **kwargs):    """    Constructor. Called in the URLconf; can contain helpful extra    keyword arguments, and other things.    """    # Go through keyword arguments, and either save their values to our    # instance, or raise an error.    for key, value in kwargs.items():      setattr(self, key, value)  @classonlymethod  def as_view(cls, **initkwargs):    """Main entry point for a request-response process."""    for key in initkwargs:      if key in cls.http_method_names:        raise TypeError("You tried to pass in the %s method name as a "    "keyword argument to %s(). Don't do that."    % (key, cls.__name__))      if not hasattr(cls, key):        raise TypeError("%s() received an invalid keyword %r. as_view "    "only accepts arguments that are already "    "attributes of the class." % (cls.__name__, key))    def view(request, *args, **kwargs):      self = cls(**initkwargs)      if hasattr(self, 'get') and not hasattr(self, 'head'):        self.head = self.get      self.request = request      self.args = args      self.kwargs = kwargs      return self.dispatch(request, *args, **kwargs)    view.view_class = cls    view.view_initkwargs = initkwargs    # take name and docstring from class    update_wrapper(view, cls, updated=())    # and possible attributes set by decorators    # like csrf_exempt from dispatch    update_wrapper(view, cls.dispatch, assigned=())    return view  def dispatch(self, request, *args, **kwargs):    # Try to dispatch to the right method; if a method doesn't exist,    # defer to the error handler. Also defer to the error handler if the    # request method isn't on the approved list.    if request.method.lower() in self.http_method_names:      handler = getattr(self, request.method.lower(), self.http_method_not_allowed)    else:      handler = self.http_method_not_allowed    return handler(request, *args, **kwargs)  def http_method_not_allowed(self, request, *args, **kwargs):    logger.warning(      'Method Not Allowed (%s): %s', request.method, request.path,      extra={'status_code': 405, 'request': request}    )    return HttpResponseNotAllowed(self._allowed_methods())  def options(self, request, *args, **kwargs):    """Handle responding to requests for the OPTIONS HTTP verb."""    response = HttpResponse()    response['Allow'] = ', '.join(self._allowed_methods())    response['Content-Length'] = '0'    return response  def _allowed_methods(self):    return [m.upper() for m in self.http_method_names if hasattr(self, m)]

注意:

(1)as_view方法:

as_view是一个类方法,因此views.LoginView.as_view()需要添加(),这样才调用这个类方法。

as_view执行完,返回是view(函数名)。因此login一旦被用户访问,真正被执行是view函数。

(2)view方法:

view函数的返回值:

return self.dispatch(request, *args, **kwargs)

这里的self是谁取决于view函数是谁调用的。view――》as_view――》LoginView(View的子类)。在子类没有定义dispatch的情况下,调用父类的。

self.dispatch(request, *args, **kwargs)是执行dispatch函数。由此可见login访问,真正被执行的是dispatch方法。且返回结果是dispatch的返回结果,且一路回传到页面显示。用户看的页面是什么,完全由self.dispatch决定。

(3)dispatch方法: (分发)

request.method.lower():这次请求的请求方式小写。

self.http_method_names:['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

判断请求方式是否在这个请求方式列表中。

handler就是反射得到的实例方法get,如果找不到则通过http_method_not_allowed返回报错。

3、自定义dispatch

from django.shortcuts import render, HttpResponsefrom django.views import Viewclass LoginView(View):  def dispatch(self, request, *args, **kwargs):    print("dispath...")    # return HttpResponse("自定义")     # 两种写法    # ret = super(LoginView, self).dispatch(request, *args, **kwargs)    # ret = super().dispatch(request, *args, **kwargs)    # return ret   def get(self, request):    print("get.....")    return render(request, "login.html")   def post(self, request):    print("post....")    return HttpResponse("post...")   def put(self, request):    pass

注意:有两种继承父类dispatch方法的方式:

ret = super(LoginView, self).dispatch(request, *args, **kwargs)ret = super().dispatch(request, *args, **kwargs)

四、postman

谷歌的一个插件,模拟前端发get post put delete请求,下载,安装。 https://www.getpostman.com/apps

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


  • 上一条:
    Django获取该数据的上一条和下一条方法
    下一条:
    django+tornado实现实时查看远程日志的方法
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Filament v3.1版本发布(0个评论)
    • docker + gitea搭建一个git服务器流程步骤(0个评论)
    • websocket的三种架构方式使用优缺点浅析(0个评论)
    • ubuntu20.4系统中宿主机安装nginx服务,docker容器中安装php8.2实现运行laravel10框架网站(0个评论)
    • phpstudy_pro(小皮面板)中安装最新php8.2.9版本流程步骤(0个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2018-05
    • 2020-02
    • 2020-03
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-11
    • 2021-03
    • 2021-09
    • 2021-10
    • 2021-11
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-08
    • 2023-08
    • 2023-10
    • 2023-12
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客