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中的Numpy入门教程
Apr 26 Python
使用Python写CUDA程序的方法
Mar 27 Python
对python中raw_input()和input()的用法详解
Apr 22 Python
python中字符串内置函数的用法总结
Sep 13 Python
python入门:这篇文章带你直接学会python
Sep 14 Python
Python做智能家居温湿度报警系统
Sep 25 Python
对json字符串与python字符串的不同之处详解
Dec 19 Python
对Python信号处理模块signal详解
Jan 09 Python
python实现斗地主分牌洗牌
Jun 22 Python
Python单元测试及unittest框架用法实例解析
Jul 09 Python
Python包管理工具pip的15 个使用小技巧
May 17 Python
Python绘制散乱的点构成的图的方法
Apr 21 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判断数组元素中是否存在某个字符串的方法
2014/06/14 PHP
php遍历CSV类实例
2015/04/14 PHP
PHP中递归的实现实例详解
2017/11/14 PHP
JS 实现完美include载入实现代码
2010/08/05 Javascript
js focus不起作用的解决方法(主要是因为dom元素是否加载完成)
2010/11/05 Javascript
超酷的网页音乐播放器DewPlayer使用方法
2010/12/18 Javascript
js中eval详解
2012/03/30 Javascript
javascript真的不难-回顾一下基础知识
2013/01/15 Javascript
js简易namespace管理器 实例代码
2013/06/21 Javascript
javascript与有限状态机详解
2014/05/08 Javascript
js操作模态窗口及父子窗口间相互传值示例
2014/06/09 Javascript
Bootstrap3 图片(响应式图片&amp;图片形状)
2017/01/04 Javascript
Bootstrap3下拉菜单的实现
2017/02/22 Javascript
浅谈vue的几种绑定变量的值 防止其改变的方法
2018/03/01 Javascript
原生js封装的ajax方法示例
2018/08/02 Javascript
微信小程序使用map组件实现获取定位城市天气或者指定城市天气数据功能
2019/01/22 Javascript
微信小程序按钮点击跳转页面详解
2019/05/06 Javascript
浅谈Vue3.0之前你必须知道的TypeScript实战技巧
2019/09/11 Javascript
使用python绘制人人网好友关系图示例
2014/04/01 Python
Python 如何访问外围作用域中的变量
2016/09/11 Python
Python进程间通信Queue实例解析
2018/01/25 Python
python正则表达式爬取猫眼电影top100
2018/02/24 Python
Flask之请求钩子的实现
2018/12/23 Python
python scp 批量同步文件的实现方法
2019/01/03 Python
Python安装Flask环境及简单应用示例
2019/05/03 Python
Python如何使用BeautifulSoup爬取网页信息
2019/11/26 Python
使用Keras实现简单线性回归模型操作
2020/06/12 Python
Html5 new XMLHttpRequest()监听附件上传进度
2021/01/14 HTML / CSS
西班牙香水和化妆品网上商店:Douglas
2017/10/29 全球购物
亚马逊海外购:亚马逊美国、英国、日本、德国直邮
2021/03/18 全球购物
毕业生物理教师求职信
2013/10/17 职场文书
仲裁协议书
2014/09/26 职场文书
2014年语文教研组工作总结
2014/12/06 职场文书
幼儿园老师新年寄语2015
2014/12/08 职场文书
《认识钟表》教学反思
2016/02/16 职场文书
Python包argparse模块常用方法
2021/06/04 Python