Django基础三之视图函数的使用方法


Posted in Python onJuly 18, 2019

一 Django的视图函数view

一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。

响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。

无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你当前项目目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为views.py的文件中。

一个简单的视图

下面是一个以HTML文档的形式返回当前日期和时间的视图:

from django.http import HttpResponse
import datetime

def current_datetime(request):
  now = datetime.datetime.now()
  html = "<html><body>It is now %s.</body></html>" % now
  return HttpResponse(html)

让我们来逐行解释下上面的代码:

首先,我们从 django.http模块导入了HttpResponse类,以及Python的datetime库。

接着,我们定义了current_datetime函数。它就是视图函数。每个视图函数都使用HttpRequest对象作为第一个参数,并且通常称之为request

注意,视图函数的名称并不重要;不需要用一个统一的命名方式来命名,以便让Django识别它。我们将其命名为current_datetime,是因为这个名称能够比较准确地反映出它实现的功能。

这个视图会返回一个HttpResponse对象,其中包含生成的响应。每个视图函数都负责返回一个HttpResponse对象。

Django使用请求和响应对象来通过系统传递状态。

当浏览器向服务端请求一个页面时,Django创建一个HttpRequest对象,该对象包含关于请求的元数据。然后,Django加载相应的视图,将这个HttpRequest对象作为第一个参数传递给视图函数。

每个视图负责返回一个HttpResponse对象。视图层,熟练掌握两个对象即可:请求对象(request)和响应对象(HttpResponse)

二 CBV和FBV

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

之前都是FBV模式写的代码,所以就不写例子了。

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

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

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

如果我们要写一个处理GET方法的view,用函数写的话是下面这样。

def login(request):
  if request.method == 'GET':
   return render(request, 'login.html')

如果用class-based view写的话,就是下面这样:

#类写法:
class LoginView(View):
  def get(self,request):
   print('get方法执行了')
   return render(request,'login2.html')
  def post(self,request):
    username=request.POST.get('username')
    password=request.POST.get('password')
    print('post方法执行了')
    print(username,password)
    return HttpResponse('cg')

Django的url是将一个请求分配给可调用的函数的,而不是一个class。针对这个问题,class-based view提供了一个as_view()静态方法(也就是类方法),调用这个方法,会创建一个类的实例,然后通过实例调用dispatch()方法,dispatch()方法会根据request的method的不同调用相应的方法来处理request(如get(),post()等)。到这里,这些方法和function-based view差不多了,要接收request,得到一个response返回。如果方法没有定义,会抛出HttpResponseNotAllowed异常。

注意:使用CBV时,urls.py中也做对应的修改::

from django.conf.urls import url,include
from django.contrib import admin
from app01 import views

urlpatterns = [
  url(r'^admin/', admin.site.urls),
  url(r'^login2/$', LoginView.as_view()),

]

CBV传参,和FBV类似,有名分组,无名分组

url写法:无名分组的

url(r'^cv/(\d{2})/', views.Myd.as_view(),name='cv'),
 url(r'^cv/(?P<n>\d{2})/', views.Myd.as_view(name='xxx'),name='cv'),#如果想给类的name属性赋值,前提你的Myd类里面必须有name属性(类属性,定义init方法来接受属性行不通,但是可以自行研究一下,看看如何行通,意义不大),并且之前类里面的name属性的值会被覆盖掉

三 使用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写在左边。

四 给视图加装饰器使用装饰器装饰FBV

FBV本身就是一个函数,所以和给普通的函数加装饰器无差:

from django.shortcuts import render, HttpResponse, redirect
def wrapper(f):
  def innser(*args, **kwargs):
   print('执行前')
   ret = f(*args, **kwargs)
   print('执行后')
   return ret
  return innser

@wrapper
def index(request):
  print('12321')
  return render(request, 'index.html')

使用装饰器装饰CBV

类中的方法与独立函数不完全相同,因此不能直接将函数装饰器应用于类中的方法 ,我们需要先将其转换为方法装饰器。

Django中提供了method_decorator装饰器用于将函数装饰器转换为方法装饰器。

def wrapper(f):
  def innser(*args, **kwargs):
   print('执行前')
   ret = f(*args, **kwargs)
   print('执行后')
   return ret

  return innser

from django.views import View
from django.utils.decorators import method_decorator
@method_decorator(wrapper,name='get')
class LoginView(View):
  # 使用CBV时要注意,请求过来后会先执行dispatch()这个方法,如果需要批量对具体的请求处理方法,如get,post等做一些操作的时候,这里我们可以手动改写dispatch方法,这个dispatch方法就和在FBV上加装饰器的效果一样。
  # @method_decorator(wrapper)
  def dispatch(self, request, *args, **kwargs):
    # print('之前')
    ret=super().dispatch(request, *args, **kwargs)
    # print('之后')
    return ret

  # @method_decorator(wrapper)
  def get(self,request):
    print('get方法执行了')
    return render(request,'login2.html')

  # @method_decorator(wrapper)
  def post(self,request):
    username=request.POST.get('username')
    password=request.POST.get('password')
    print('post方法执行了')
    print(username,password)
    return HttpResponse('cg')

另外给cbv添加装饰器的时候(先作为了解):

直接添加在dispatch里面,这样每个函数都会执行

from django.utils.decorators import method_decorator

@method_decorator(login_test)
def dispatch(self, request, *args, **kwargs):
res = super(IndexView, self).dispatch(request, *args, **kwargs)
return res

添加在每一个函数中

from django.utils.decorators import method_decorator

@method_decorator(login_test)
def get(self, request, *args, **kwargs):
return render(request, 'index.html')

直接添加在类上,后面的name表示只给get添加装饰器

from django.utils.decorators import method_decorator

@method_decorator(login_test, name='get')

get是给get方法加 (以这种方式如果想给多个方法加装饰器,需要写多层装饰器,因为name这个参数的值必须是个字符串,并且不能同时写两个方法)

@method_decorator(login_test, name='post') post是给post方法加
  class IndexView(View):


def get(self,request):



pass

添加装饰器前必须导入from django.utils.decorators import method_decorator

添加装饰器的格式必须为@method_decorator(),括号里面为装饰器的函数名

给类添加是必须声明name

注意csrf-token装饰器的特殊性,在CBV模式下它只能加在dispatch上面(后面再说)

下面这是csrf_token的装饰器:

@csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置csrfToken全局中间件。

@csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

注意:from django.views.decorators.csrf import csrf_exempt,csrf_protect

五 request对象官方文档

请求相关的属性方法(request--HttpRequest对象)

def index(request): #http相关请求信息---封装--HttpRequest对象

  if request.method == 'GET':
    print(request.body) #获取post请求提交过来的原始数据
    print(request.GET)  #获取GET请求提交的数据
    # print(request.META) # 请求头相关信息,就是一个大字典
    print(request.path) #/index/ 路径
    print(request.path_info) #/index/ 路径
    print(request.get_full_path()) #/index/?username=dazhuang&password=123
    
    return render(request,'index.html')
  else:
    print(request.body) # b'username=dazhuang'
    print(request.POST) #获取POST请求提交的数据
    return HttpResponse('男宾三位,拿好手牌!')

六 response对象

与由Django自动创建的HttpRequest对象相比,HttpResponse对象是我们的职责范围了。我们写的每个视图都需要实例化,填充和返回一个HttpResponse。

HttpResponse类位于django.http模块中。

HttpResponse --- 回复字符串的时候来使用
render --- 回复一个html页面的时候使用
redirect -- 重定向
  示例:
  def login(request):
    if request.method == 'GET':
      return render(request,'login.html')
    else:
      username = request.POST.get('username')
      password = request.POST.get('password')
      if username == 'taibai' and password == 'dsb':
        # return render(request,'home.html')
        return redirect('/home/') #重定向
      else:
        return HttpResponse('滚犊子,赶紧去充钱!!!')

  #首页
  def home(request):
    return render(request,'home.html')
  
  
HttpResponse.content:响应内容
HttpResponse.charset:响应内容的编码
HttpResponse.status_code:响应的状态码

redirect() :给浏览器了一个30x的状态码

参数可以是:

一个模型:将调用模型的get_absolute_url() 函数

 2.一个视图,可以带有参数:将使用urlresolvers.reverse 来反向解析名称

 3.一个绝对的或相对的URL,将原封不动的作为重定向的位置。

 默认返回一个临时的重定向;传递permanent=True 可以返回一个永久的重定向。

 示例:

​ 你可以用多种方式使用redirect() 函数。

def login(request):
  if request.method == 'GET':
   return render(request, 'login.html')
  else:
   username = request.POST.get('username')
   password = request.POST.get('password')
   if username == 'anwen@123' and password == '123':
     return redirect('/app01/home/') ##重定向到/app01/home/路径,这也是发送了一个请求,别忘了在上面引入这个redirect类,和render、Httpresponse在一个地方引入
   else:
     return HttpResponse('登录失败!')


def home(request):
  return render(request, 'home.html')
#app01里的 urls.py
from django.conf.urls import url
from app01 import views
urlpatterns=[
  url(r'^$',views.login),
  url(r'^home/',views.home),
]

上面几个文件搞好之后,我们重启Django项目,然后登陆页面的输入网址,注意,你输入的网址端口要和你启动的django项目的端口一样。

Django基础三之视图函数的使用方法

| 一点击提交按钮,你看一下network里面发送了几个请求:两个请求,一个是login请求,一个index请求。 |

Django基础三之视图函数的使用方法

扩展阅读:** key两次请求,关于301和302:

 

1)301和302的区别。

301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址可以从响应的Location首部中获取
(用户看到的效果就是他输入的地址A瞬间变成了另一个地址B)——这是它们的共同点。

他们的不同在于。301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;

302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。 SEO302好于301

2)重定向原因:

(1)网站调整(如改变网页目录结构);
(2)网页被移到一个新地址;
(3)网页扩展名改变(如应用需要把.php改成.Html或.shtml)。

这种情况下,如果不做重定向,则用户收藏夹或搜索引擎数据库中旧地址只能让访问客户得到一个404页面错误信息,访问流量白白丧失;再者某些注册了多个域名的网站,也需要通过重定向让访问这些域名的用户自动跳转到主站点等。

临时重定向(响应状态码:302)和永久重定向(响应状态码:301)对普通用户来说是没什么区别的,它主要面向的是搜索引擎的机器人。

  1. A页面临时重定向到B页面,那搜索引擎收录的就是A页面。
  2. A页面永久重定向到B页面,那搜索引擎收录的就是B页面。
  3. 用redirect可以解释APPEND_SLASH的用法!

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

Python 相关文章推荐
python操作xml文件详细介绍
Jun 09 Python
Python连接DB2数据库
Aug 27 Python
Python随机数用法实例详解【基于random模块】
Apr 18 Python
python装饰器-限制函数调用次数的方法(10s调用一次)
Apr 21 Python
python批量替换多文件字符串问题详解
Apr 22 Python
Python定时发送消息的脚本:每天跟你女朋友说晚安
Oct 21 Python
python 返回列表中某个值的索引方法
Nov 07 Python
解决os.path.isdir() 判断文件夹却返回false的问题
Nov 29 Python
Python生成器常见问题及解决方案
Mar 21 Python
社区版pycharm创建django项目的方法(pycharm的newproject左侧没有项目选项)
Sep 23 Python
Django admin组件的使用
Oct 24 Python
PyMongo 查询数据的实现
Jun 28 Python
详解python实现小波变换的一个简单例子
Jul 18 #Python
Django基础知识 URL路由系统详解
Jul 18 #Python
对Django项目中的ORM映射与模糊查询的使用详解
Jul 18 #Python
Django基础知识 web框架的本质详解
Jul 18 #Python
django 使用全局搜索功能的实例详解
Jul 18 #Python
Django中Middleware中的函数详解
Jul 18 #Python
对DJango视图(views)和模版(templates)的使用详解
Jul 17 #Python
You might like
PHP的简易冒泡法代码分享
2012/08/28 PHP
php简单浏览目录内容的实现代码
2013/06/07 PHP
php实现向javascript传递数组的方法
2015/07/27 PHP
2款PHP无限级分类实例代码
2015/11/11 PHP
关于jquery ajax 调用带参数的webservice返回XML数据一个小细节
2012/07/31 Javascript
JS实现控制表格行文本对齐的方法
2015/03/30 Javascript
javascript格式化日期时间方法汇总
2015/06/19 Javascript
jquery实现浮动在网页右下角的彩票开奖公告窗口代码
2015/09/04 Javascript
javascript实现2016新年版日历
2016/01/25 Javascript
Angular移动端页面input无法输入的解决方法
2017/11/14 Javascript
使用wxapp-img-loader自定义组件实现微信小程序图片预加载功能
2018/10/18 Javascript
PWA介绍及快速上手搭建一个PWA应用的方法
2019/01/27 Javascript
每天学点Vue源码之vm.$mount挂载函数
2019/03/11 Javascript
基于Vue实现平滑过渡的拖拽排序功能
2019/06/12 Javascript
详解element-ui设置下拉选择切换必填和非必填
2019/06/17 Javascript
vue 使用axios 数据请求第三方插件的使用教程详解
2019/07/05 Javascript
用webAPI实现图片放大镜效果
2020/11/23 Javascript
python实现的防DDoS脚本
2011/02/08 Python
Python代码调试的几种方法总结
2015/04/15 Python
python利用rsa库做公钥解密的方法教程
2017/12/10 Python
Python2中文处理纪要的实现方法
2018/03/10 Python
python利用faker库批量生成测试数据
2020/10/15 Python
CSS3中Transition动画属性用法详解
2016/07/04 HTML / CSS
HTML5中drawImage用法分析
2014/12/01 HTML / CSS
美国嘻哈首饰购物网站:Hip Hop Bling
2016/12/30 全球购物
美国最大的存储市场:SpareFoot
2018/07/23 全球购物
Tomcat中怎么使用log4j输出所有的log
2016/07/07 面试题
Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?用contains来区分是否有重复的对象。还是都不用
2013/07/30 面试题
竞选班干部的演讲稿
2014/04/24 职场文书
《特殊的葬礼》教学反思
2014/04/27 职场文书
业务员岗位职责范本
2015/04/03 职场文书
2015初一年级组工作总结
2015/07/24 职场文书
2015年社区重阳节活动总结
2015/07/30 职场文书
幼儿园安全管理制度
2015/08/05 职场文书
Python爬虫之爬取哔哩哔哩热门视频排行榜
2021/04/28 Python
vue+iview实现手机号分段输入框
2022/03/25 Vue.js