6. django 博客首页视图

本教程内容已过时,更新版教程请访问: Django 博客开发入门教程

这是 Django 博客教程的第 6 篇,在阅读此篇教程以前,请确保你已阅读 Django 博客教程的前 5 篇:
1. Django 博客教程:前言
2. 搭建开发环境
3. 建立我们的 django 博客应用
4. 创建 django 博客的数据库模型
5. 让 django 完成翻译——迁移数据库模型

django 是如何处理 http 请求的

Web 应用的交互过程其实就是 http 请求与响应的过程。无论是在 PC 端还是移动端,我们通常使用浏览器来上网,我们的上网流程大致来说是这样的:

  1. 我们打开浏览器,在地址栏输入我们想访问的网址,比如 www.djangoproject.com(当然你也可能从收藏夹里直接打开网站,但本质上都是一样的。)
  2. 浏览器知道我们想要访问那个网址后,它在后台帮我们做了很多事情,主要就是把我们的访问意图包装成一个 http 请求,发给我们想要访问的网址所对应的服务器。通俗点说就是浏览器帮我们通知网站的服务器,说有人来访问你啦,访问的请求都写在 http 里了,你按照要求处理后告诉我,我再帮你回应他!
  3. 网站服务器处理了 http 请求,然后生成一段 http 响应给浏览器,浏览器解读这个响应,把相关的内容在浏览器里显示出来,于是我们就看到了网站的内容。比如你访问了社区主页 www.pythonzh.cn,服务器接收到这个请求后他就知道用户访问的是首页,首页显示的是全部帖子列表,于是它从数据库里把帖子数据取出来,生成一个写着这些数据的 html 文档,包装到 http 响应里发给浏览器,浏览器解读这个响应,把 html 文档显示出来,我们就看到了帖子列表的内容。

因此,django 作为一个 web 框架,它的使命就是处理流程中的第二步,接收浏览器发来的 http 请求,返回相应的 http 响应。于是引出这么几个问题:

  1. django 如何接收 http 请求?
  2. django 如何处理这个 http 请求?
  3. 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 中写入这些代码:

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
]

我们首先从 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 文件里:

blog/views.py

from django.http import HttpResponse

def index(request):
    return HttpResponse("欢迎访问我的博客首页!")

我们前面说过,Web 服务器的作用就是接收来自用户的 http 请求,根据请求内容作出相应的处理,并把处理结果包装成 http 响应返回给用户。这个两行的函数体现了这个过程。它首先接受了一个名为 request 的参数,这个 request 就是 django 为我们封装好的 http 请求,它是类 HttpResponse 的一个实例。然后我们便直接返回了一个 http 响应给用户,这个 http 响应也是 django 帮我们封装好的,它是类 HttpResponse 的一个实例,只是我们给它传了一个自定义的字符串,用户接受到这个响应后就会在浏览器显示出我们传递的内容:“欢迎访问我的博客首页!”

还差最后一步了,我们前面建立了一个 urls.py 文件,并且绑定了 URL 和视图函数 index,但是 django 并不知道。django 匹配 url 是在 blogproject 的 urls.py 下的,所以我们要把我们自己写的 urls.py 文件包含到这个文件里去,打开这个文件看到如下内容:

"""
一大段注释
"""

from django.conf.urls import url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

修改成如下的形式:

- from django.conf.urls import url
+ from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
+   url(r'', include('blog.urls')),
]

这里 - 表示删掉这一行,+ 表示添加这一行。我们这里导入了一个 include 函数,然后利用这个函数把 blog 应用下的 urls.py 包含了进来。此外 include 前还有一个 r'',这是一个空字符串,这里也可以写其他字符串,django 会把这个字符串和后面 include 的 urls.py 文件中的 url 拼接。假如我们这里把 r'' 改成 r'blog/',而我们在 blog.urls 中写的url 是 r'^$',一个空字符串,那么 django 最终匹配的就是 blog/ 加上一个空字符串,即 blog/。

运行 python manage.py runserver 打开开发服务器,在浏览器输入开发服务器的地址 http://127.0.0.1:8000/,可以看到我们返回的内容了:欢迎访问我的博客首页!

这基本上就上 django 的开发流程了,写好处理 http 请求和返回 http 响应的视图函数,然后把视图函数绑定到相应的 URL 上。但是等一等!我们看到在我们的视图函数里返回的是一个 HttpResponse 类的实例,我们给他传入了一个我们希望显示在用户浏览器上的字符串。但是我们的博客不可能只显示这么一句话,它有可能会显示很长很长的内容,比如我们发布的博客文章列表,或者一大段的博客文章,我们不能每次都把这些大段大段的内容传给 HttpResponse 。于是 django 对这个问题给我们提供了一个好的方法,叫做模板系统。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 文件里设置一下模板文件所在的路径。在 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'),变成这样:

blogproject/settings.py

TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        ...
    },
]

这里 BASE_DIR 是 settings.py 前面定义的变量,记录的是工程根目录 blogproject 的值,在这个目录下有我们的模板目录 templates,于是利用os.path.join 把这两个路径连起来,构成完整的模板路径,django 就知道去这个路径下面找我们的模板了。

视图函数可以改一下了:

blog/views.py

from django.http import HttpResponse
from django.shortcuts import render

def index(request):
    return render(request, 'blog/index.html', context={
                      'title': '我的博客首页', 
                      'welcome': '欢迎访问我的博客首页'
                  })

这里我们在是直接把字符串传给 HttpResponse 了,而是调用 django 提供了 render 函数,这个函数根据我们传入的参数来构造 HttpResponse。我们首先把 http 请求传了进去,然后它根据第二个参数的值 blog/index.html 找到我们的模板,然后读取模板中的内容,并且根据我们传入的 context 把模板中的变量替换为我们传递的值,{{ title }} 被替换成了 context 字典中 title 对应的值,同理 {{ welcome }} 也被替换成相应的值。最终,我们的 html 模板中的内容字符串被传递给 HttpResponse 对象并返回给浏览器,这样用户的浏览器上便显示出了我们写的 html 模板的内容。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容