一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求而且返回Web响应。php
响应能够是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。html
不管视图自己包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你当前项目目录下面。除此以外没有更多的要求了——能够说“没有什么神奇的地方”。为了将代码放在某处,你们约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为views.py
的文件中。python
下面是一个以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
首先,咱们从 django.http
模块导入了HttpResponse
类,以及Python的datetime
库。编程
接着,咱们定义了current_datetime
函数。它就是视图函数。每一个视图函数都使用HttpRequest
对象做为第一个参数,而且一般称之为request
。浏览器
注意,视图函数的名称并不重要;不须要用一个统一的命名方式来命名,以便让Django识别它。咱们将其命名为current_datetime
,是由于这个名称可以比较准确地反映出它实现的功能。服务器
这个视图会返回一个HttpResponse
对象,其中包含生成的响应。每一个视图函数都负责返回一个HttpResponse
对象。app
Django使用请求和响应对象来经过系统传递状态。编程语言
当浏览器向服务端请求一个页面时,Django建立一个HttpRequest对象,该对象包含关于请求的元数据。而后,Django加载相应的视图,将这个HttpRequest对象做为第一个参数传递给视图函数。
每一个视图负责返回一个HttpResponse对象。视图层,熟练掌握两个对象便可:请求对象(request)和响应对象(HttpResponse)
FBV(function base views) 就是在视图里使用函数处理请求。
以前都是FBV模式写的代码,因此就不写例子了。
CBV(class base views) 就是在视图里使用类处理请求。
Python是一个面向对象的编程语言,若是只用函数来开发,有不少面向对象的优势就错失了(继承、封装、多态)。因此Django在后来加入了Class-Based-View。可让咱们用类写View。这样作的优势主要下面两种:
若是咱们要写一个处理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属性的值会被覆盖掉
我以为要理解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自己就是一个函数,因此和给普通的函数加装饰器无差:
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
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('男宾三位,拿好手牌!')
与由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:响应的状态码
参数能够是:
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项目的端口同样。
| 一点击提交按钮,你看一下network里面发送了几个请求:两个请求,一个是login请求,一个index请求。 |
扩展阅读:** 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)对普通用户来讲是没什么区别的,它主要面向的是搜索引擎的机器人。 A页面临时重定向到B页面,那搜索引擎收录的就是A页面。 A页面永久重定向到B页面,那搜索引擎收录的就是B页面。 用redirect能够解释APPEND_SLASH的用法!