声明:此Django分类下的教程是追梦人物所有,地址http://www.jianshu.com/u/f0c09f959299,本人写在此只是为了巩固复习使用
django 是如何处理 http 请求的
web应用的交互过程其实就是http请求和响应的过程,我们使用浏览器上网流程大致上是这样的:
- 我们打开浏览器,在地址栏输入我们想访问的网址,比如 www.djangoproject.com(当然你也可能从收藏夹里直接打开网站,但本质上都是一样的。)
- 浏览器知道我们要访问那个网址后,它在后台帮我们做了很多事,主要就是把我们的访问以图包装成一个http请求,发给我们想要访问的网址所对应的服务器,通俗点将就是浏览器帮我们通知网站的服务器,说有人来访问你了,访问的请求都写在了http里了,你按照要求处理后告诉我,我再帮你回应
- 网站服务器处理了http请求,然后生成一段http响应给浏览器,浏览器解读这个响应,把相关内容在浏览器里显示出来,于是我们就看到了网站的内容
因此,django 作为一个 web 框架,它的使命就是处理流程中的第二步,接收浏览器发来的 http 请求,返回相应的 http 响应。于是引出这么几个问题:
- django 如何接收 http 请求?
- django 如何处理这个 http 请求?
- django 如何生成 http 响应?
对于如何处理这些问题,django 有其自身的一套规定的机制。我们按照 django 的规定,就能开发出我们所需的功能。我们先以一个最简单的 hello world 为例来看看 django 处理上述问题的机制是怎么样的。
首先 django 需要知道当用户访问不同的网址时,应该如何处理不同的网址。django 的做法是把不同的网址对应的处理函数写在一个 urls.py 文件里,当用户访问某个网址时,django 就去会这个文件里找,如果找到这个网址,就会调用和它绑定在一起的处理函数(叫做视图函数),下面是具体的做法,首先在 blog 应用的目录下创建一个 urls.py 文件,这时你的目录看起来是这样:
blog/ __init__.py admin.py apps.py migrations/ 0001_initial.py __init__.py models.py tests.py views.py urls.py # 新建的文件
在urls.py写入这些代码
1 from django.conf.urls import url 2 from . import views 3 4 5 urlpatterns = [ 6 # 第一个参数是网址,第二个是处理函数 7 url(r'^$', views.index, name='index') 8 ]
我们首先从django.conf.urls 导入了url函数,从当前目录导入了views模块,然后我们把网址和处理函数的关系卸载了urlpatterns列表里。绑定关系的写法是把网址和对应的处理函数作为参数写给url函数,另外传递了一个name参数,这个参数的值将作为处理函数index的别名,这在以后会用到
注意这里我们的网址是用正则写的,django会用这个正则去匹配用户实际输入的网址,如果匹配成功就会调用后面的视图函数做相应的处理,比如说我们本地开发服务器的域名是 127.0.0.1:8000,那么当用户输入网址:127.0.0.1:8000 后,django 首先会把域名(即 127.0.0.1)和端口号(8000)去掉,此时只剩下一个空字符串,而 r'^$' 的模式正是匹配一个空字符串(这个正则表达式的意思是以空字符串开头且以空字符串结尾),于是二者匹配,django 便会调用其对应的 views.index 函数。
第二步就是实际编写我们的views.index视图函数了,卸载views.py文件里:
from django.shortcuts import render from django.http import HttpResponse # Create your views here. def index(request): return HttpResponse('Welcome to my blog home!')
前面说过,web服务器的作用就是接收来自用户的http请求,根据请求内容做出相应的处理,并把处理结果包装成http响应返回给用户,这个两行的函数体现了这个过程,它首先接受了一个request参数,这个request就是django为我们封装好的http请求,他是类httpresponse的一个实例,然后我们便直接返回了一个http响应给用户,这个http响应也是django帮我们封装好的,也是类httpresponse的一个实例,只是我们给它传了一个自定义的字符串,用户接受到这个响应后就会在浏览器显示出我们传递的内容'Welcome to my blog home!'
还差最后一步,我们前面建立了一个urls.py文件,并且绑定了url和视图函数index,但是django并不知道,django匹配url是在NewprojectBlog的urls.py下的,所以我们要把我们自己写的urls.py文件包含到这个文件里去
打开这个文件我们看到以下内容
"""NewBlogProject URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.10/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf.urls import url from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), ]
我们在urlpatterns列表中加入url(r'', include(blog.urls)),include方法需要导入,写from django,conf.urls import include
include函数把blog应用下的urls.py包含了进来,此外include前面还有一个r'‘,这是一个空字符串,这里也可以写成其它的字符串,django会把这个字符串和后面include包含的urls.py文件里的url拼接,例如我们把这里的r'‘改成r'blog/',而我们在blog.urls中写的url是r'^$'一个空字符串,那么django最终匹配的就是blog/加上一个空字符串
这基本上就是django的开发流程了,写好处理http请求和返回http响应的师徒函数,然后把视图函数绑定到相应的url上,但是我们在视图函数中返回的是一个HTTPResponse类的实例,我们给他传入了一个我们希望显示在用户浏览器上的字符串,但是我们的blog不可能只显示一句话,它有可能会显示很长很长的内容,比如我们发布的博客文章列表,或者一大段的博客文字,我们不能每次都把这些大段段的内容传递给HTTPResponse,于是django对这个问题提供了一个好方法,叫做模版系统,django要我们把大段的文本写到一个文件里,然后自己会去读取这个文件,django再把读取到的内容传递给HTTPResponse,我们用模版系统来改造一下上面的例子。在项目目录里有一个templates的文件夹,用来存放我们的模版,然后再建立一个blog文件夹,用来存放blog应用相关的模版,淡然存放在那里不重要,只要django找的到就行,但是这样建立的目地是把不同应用用的模块分离开来,方便维护,然后在新建的blog下建立一个index.html文件,写下代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{ title }}</title> </head> <body> <h1>{{ welcome }}</h1> </body> </html>
这是一个标准的html文档,只是里面有两个比较奇怪的地方,{{title}}和{{welcome}},这是django规定的语法,用{{}}包起来的叫做模版变量,django在读取这个模版的时候会根据我们传来的值替换这些变量,最终在模版中显示的将会是我们传递的值。
模版写好了还得告诉django去那里找模版,在settings.py文件里设置一下模版文件的路径,找到TEMPLATES选项,
blogproject/settings.py TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
其中的DIRS就是设置模版的路径,写入os.path.join(BASE_DIR, 'templates')
这里的BASE_DIR是settings.py前面定义的变量,记录的是工程目录newprojectblog的值。在这里目录下有我们的模版目录templates,于是利用os.path.join把两个路径连起来,构成完整的模版路径,django就知道去这个路径下面找我们的模版
视图函数可以改一下了
from django.shortcuts import render from django.http import HttpResponse # Create your views here. def index(request): return render(request, 'blog/index.html', context={'title': 'My blog home', 'welcome': 'Welcome to my blog!'})
这里我们不在是把字符串传递给HttpResponse了,而是调用django提供的 render函数,这个函数根据我们传入的参数来构造HttpResponse,我们首先把http请求传了进去,然后它根据第二个参数的值blog/index.html找到我们的模版,然后读取模版的内容,并且根据我们传入的context把模版中的变量替换成我们传递的值,{{ title }} 被替换成了 context 字典中 title 对应的值,同理 {{ welcome }} 也被替换成相应的值。最终,我们的 html 模板中的内容字符串被传递给 HttpResponse 对象并返回给浏览器,这样用户的浏览器上便显示出了我们写的 html 模板的内容。