​第 05 篇:Django 的接客之道

发布时间:2024-12-13  

作者:HelloGitHub-追梦人物

文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库[1] 

点击本文最下方的“阅读原文”即可获取

Web 服务简单的说就是处理请求,每个请求就像是一个“顾客”。首先热情地把顾客迎接进来,然后满足用户的个性化需求,最后让顾客心满意足的离开。Django 作为一个 web 框架,能够让开发者有更多的精力和时间去应付复杂多变的需求,而不是把时间花费在招店小二、做饭的厨子、服务员等。那么下面我们就来看看 Django 的接客之道吧。

Django 处理 HTTP 请求

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

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

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

1.django 如何接收 HTTP 请求?2.django 如何处理这个 HTTP 请求?3.django 如何生成 HTTP 响应?

对于如何处理这些问题,django 有其一套规定的机制。我们按照 django 的规定,就能开发出所需的功能。

Hello 视图函数

我们先以一个最简单的 Hello World 为例来看看 django 处理上述问题的机制是怎么样的。

绑定 URL 与视图函数

首先 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

在 blogurls.py 中写入这些代码:

from django.urls import path
from . import views
urlpatterns = [ path('', views.index, name='index'),]

我们首先从 django.urls 导入了 path 函数,又从当前目录下导入了 views 模块。然后我们把网址和处理函数的关系写在了 urlpatterns 列表里。

绑定关系的写法是把网址和对应的处理函数作为参数传给 path 函数(第一个参数是网址,第二个参数是处理函数),另外我们还传递了另外一个参数 name,这个参数的值将作为处理函数 index 的别名,这在以后会用到。

注意这里我们的网址实际上是一个规则,django 会用这个规则去匹配用户实际输入的网址,如果匹配成功,就会调用其后面的视图函数做相应的处理。

比如说我们本地开发服务器的域名是 http://127.0.0.1:8000,那么当用户输入网址 http://127.0.0.1:8000 后,django 首先会把协议 http、域名 127.0.0.1 和端口号 8000 去掉,此时只剩下一个空字符串,而 '' 的模式正是匹配一个空字符串,于是二者匹配,django 便会调用其对应的 views.index 函数。

注意

在 blogproject 目录下(即 settings.py 所在的目录),原本就有一个 urls.py 文件,这是整个工程项目的 URL 配置文件。而我们这里新建了一个 urls.py 文件,且位于 blog 应用下。这个文件将用于 blog 应用相关的 URL 配置,这样便于模块化管理。不要把两个文件搞混了。

编写视图函数

第二步就是要实际编写我们的 views.index 视图函数了,按照惯例视图函数定义在 views.py 文件里:

blog/views.py
from django.http import HttpResponse
def index(request): return HttpResponse("欢迎访问我的博客首页!")

我们前面说过,Web 服务器的作用就是接收来自用户的 HTTP 请求,根据请求内容作出相应的处理,并把处理结果包装成 HTTP 响应返回给用户。

这个两行的函数体现了这个过程。它首先接受了一个名为 request 的参数,这个request 就是 django 为我们封装好的 HTTP 请求,它是类 HttpRequest 的一个实例。然后我们便直接返回了一个 HTTP 响应给用户,这个 HTTP 响应也是 django 帮我们封装好的,它是类 HttpResponse 的一个实例,只是我们给它传了一个自定义的字符串参数。

浏览器接收到这个响应后就会在页面上显示出我们传递的内容 :欢迎访问我的博客首页!

配置项目 URL

还差最后一步了,我们前面建立了一个 urls.py 文件,并且绑定了 URL 和视图函数 index,但是 django 并不知道。django 匹配 URL 模式是在 blogproject 目录(即 settings.py 文件所在的目录)的 urls.py 下的,所以我们要把 blog 应用下的 urls.py 文件包含到 blogprojecturls.py 里去,打开这个文件看到如下内容:

blogproject/urls.py
"""一大段注释"""
from django.contrib import adminfrom django.urls import path
urlpatterns = [ path('admin/', admin.site.urls),]

修改成如下的形式:

from django.contrib import adminfrom django.urls import path, include
urlpatterns = [ path('admin/', admin.site.urls), path('', include('blog.urls')),]

我们这里导入了一个 include 函数,然后利用这个函数把 blog 应用下的 urls.py 文件包含了进来。此外 include 前还有一个 '',这是一个空字符串。这里也可以写其它字符串,django 会把这个字符串和后面 include 的 urls.py 文件中的 URL 拼接。比如说如果我们这里把 '' 改成 'blog/',而我们在 blogurls.py 中写的 URL 是 '',即一个空字符串。那么 django 最终匹配的就是 blog/ 加上一个空字符串,即 blog/。

运行结果

运行 pipenv run python manage.py runserver 打开开发服务器,在浏览器输入开发服务器的地址 http://127.0.0.1:8000/,可以看到 django 返回的内容了。

欢迎访问我的博客首页!

使用 django 模板系统

这基本上就上 django 的开发流程了,写好处理 HTTP 请求和返回 HTTP 响应的视图函数,然后把视图函数绑定到相应的 URL 上。

但是等一等!我们看到在视图函数里返回的是一个 HttpResponse 类的实例,我们给它传入了一个希望显示在用户浏览器上的字符串。但是我们的博客不可能只显示这么一句话,它有可能会显示很长很长的内容。比如我们发布的博客文章列表,或者一大段的博客文章。我们不能每次都把这些大段大段的内容传给 HttpResponse

django 对这个问题给我们提供了一个很好的解决方案,叫做模板系统。django 要我们把大段的文本写到一个文件里,然后 django 自己会去读取这个文件,再把读取到的内容传给 HttpResponse。让我们用模板系统来改造一下上面的例子。

首先在我们的项目根目录(即 manage.py 文件所在目录)下建立一个名为 templates 的文件夹,用来存放我们的模板。然后在 templates 目录下建立一个名为 blog 的文件夹,用来存放和 blog 应用相关的模板。

当然模板存放在哪里是无关紧要的,只要 django 能够找到的就好。但是我们建立这样的文件夹结构的目的是把不同应用用到的模板隔离开来,这样方便以后维护。我们在 templateslog 目录下建立一个名为 index.html 的文件,此时你的目录结构应该是这样的:

HelloDjango-blog-tutorial    manage.py     ...    templates        blog            index.html

注意

再一次强调 templates 目录位于项目根目录,而 index.html 位于 templateslog 目录下,而不是 blog 应用下,如果弄错了你可能会得到一个 TemplateDoesNotExist 异常。如果遇到这个异常,请回来检查一下模板目录结构是否正确。

在 templateslogindex.html 文件里写入下面的代码:

    {{ title }}

{{ welcome }}

这是一个标准的 HTML 文档,只是里面有两个比较奇怪的地方:{{ title }}{{ welcome }}。这是 django 规定的语法。用 {{ }} 包起来的变量叫做模板变量。django 在渲染这个模板的时候会根据我们传递给模板的变量替换掉这些变量。最终在模板中显示的将会是我们传递的值。

注意:

index.html 必须以 UTF-8 的编码格式保存,且小心不要往里面添加一些特殊字符,否则极有可能得到一个 UnicodeDecodeError 这样的错误。

模板写好了,还得告诉 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 在配置开头前面定义的变量,记录的是工程根目录 HelloDjango-blog-tutorial 的值。在这个目录下有模板文件所在的目录 templates,于是利用os.path.join 把这两个路径连起来,构成完整的模板路径,django 就知道去这个路径下面找我们的模板了。

视图函数可以改一下了:

blog/views.py
from django.shortcuts import render

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

这里我们不再是直接把字符串传给 HttpResponse 了,而是调用 django 提供的 render 函数。这个函数根据我们传入的参数来构造 HttpResponse

我们首先把 HTTP 请求传了进去,然后 render 根据第二个参数的值 blog/index.html 找到这个模板文件并读取模板中的内容。之后 render 根据我们传入的 context 参数的值把模板中的变量替换为我们传递的变量的值,{{ title }} 被替换成了 context 字典中 title 对应的值,同理 {{ welcome }} 也被替换成相应的值。

最终,我们的 HTML 模板中的内容字符串被传递给 HttpResponse 对象并返回给浏览器(django 在 render 函数里隐式地帮我们完成了这个过程),这样用户的浏览器上便显示出了我们写的 HTML 模板的内容了。

References

[1] HelloGitHub-Team 仓库: https://github.com/HelloGitHub-Team/HelloDjango-blog-tutorial


关注公众号加入交流群,一起讨论有趣的技术话题


HelloDjango 往期回顾:

第 04 篇:Django 迁移、操作数据库

第 03 篇:创建 Django 博客的数据库模型

第 02 篇:"空空如也"的博客应用

第 01 篇:开始进入 django 开发之旅


 点击 “阅读原文” 获取代码

 点击 看”

文章来源于:21IC    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

相关文章

    51单片机积累了太多的学习资料、例程、设计实例等,而且他们也非常愿意把这些资料共享出来方便后辈们学习。大学里的课程设计题目甚至毕业设计题目,在网上都能找到许多参考资料,这让很多同学更愿意在51单片机的基础上去实现自己的毕业设计......
    PNP三极管控制蜂鸣器无法完全关断-解析; -很多学生的毕业设计都用了PNP三极管去控制蜂鸣器,然后不少遇到蜂鸣器无法完全关断的问题,只是声音变小了。以下为分析思路,解决......
    EDU基于两校就业报告的内容,整合相关数据,进行可视化分析和解读。让我们一起看看,清华北大的学子们,毕业后都去哪儿了。 说明:本文中清华北大的数据均不包括港澳台和留学生。北大......
    以得到我们想要的脉冲波。 根据下面的步骤就可以输出PWM,因为使用的是PB5端口,所以需要开启TIM3的部分重映射。下面的程序可以产生LED灯亮度不断变化的效果,实际上就是呼吸灯。 之前大学的毕业设计......
    8051单片机进行8路LED模拟分支控制;一、设计题目用8051的P1口作为输入、P0口作为输出,通过74LS244接8路LED模拟分支控制。P1.0为低电平时,点亮一LED;P1.0为高......
    ​第 05 篇:Django 的接客之道; 作者:HelloGitHub-追梦人物 文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库[1]  点击本文最下方的“阅读......
    环境检测的功能。该系统能模拟汽车加油的全过程,并具备远程控制功能。 题目分析 本次毕业设计是智能加油系统的设计与实现,设计所包含的模块主要有oled显示电路、电磁阀驱动电路、可燃......
    向核心技术制高点迈进,逐步改变了中国先进半导体高端IP受制于国外的历史,目前正在重兵布局高性能计算图形GPU主流产品,改变卡脖子的局面。不少当年进入芯动科技的毕业生都在不断攻关克难中,成为顶尖行业专家。机会......
    Python基于Flask+MySQL的车辆管理系统;基于 Python+Django+ MySQL的车辆管理系统,采用Echart构建图表,支持一键切换颜色主题,通过......
    创新创意实践活动,也是“中国研究生创新实践系列大赛”主题赛事之一。在开赛之初,竞赛就确立了“以企业为主要推动力”的发展思路,企业资金支持、企业参与设计题目、企业参与评审、企业......

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>