• 进入"运维那点事"后,希望您第一件事就是阅读“关于”栏目,仔细阅读“关于Ctrl+c问题”,不希望误会!

Django视图与URL

Python框架 彭东稳 7年前 (2017-10-10) 17583次浏览 已收录 0个评论

一、Django 新建项目

安装 Django 之后,你现在应该已经有了可用的管理工具 django-admin.py。我们可以使用 django-admin.py 来创建一个项目:

注意:project_name 是自己的项目名称,需要为合法的 Python 包名,如不能为 1a 或 a-b。

创建完成后我们可以查看下项目的目录结构:

manage.py:一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。

project_name:项目的容器,此名称一旦创建后就不能更改了。

__init__.py:一个空文件,告诉 Python 该目录是一个 Python 模块。

settings.py:该 Django 项目的设置/配置文件,比如设置数据库,开启 DEBUG,设置允许访问主机,设置入口URL,设置时区等。

urls.py:该 Django 项目的URL入口文件,用户访问入口,其他所有都是通过此处路由跳转过去的,通过 settings 文件设定的。

wsgi.py:一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目,开发者不需要关注。

接下来我们进入项目目录输入以下命令,启动 Django web 服务器:

其中 0.0.0.0 让其它电脑可连接到开发服务器,8000 为端口号。如果不说明,那么端口号默认为 8000。对于新版本 Django,启动 Django 后,不能访问,报 400 错误。原因是服务端没有开启允许访问,编辑 project_name 目录下 setting.py ,把其中的 ALLOWED_HOSTS=[] 改成 ALLOWED_HOSTS=[‘*’],表示允许访问任何目标地址(一般填写服务器 IP 或域名,主要是为了方式 HTTP Host header 的一个攻击)。在浏览器输入你服务器的 IP 及端口号,如果正常启动,在浏览器访问地址会出现 “It worked!” 就表示成功了。

Django 内置的 webserver,仅仅用于开发测试,当我们更改配置文件后,内置 webserver 会自动 reload,方便开发。线上使用还是需要用 nginx 这种高性能 web 服务器。

二、视图与 URL 配置

了解完创建一个项目之后,来写一个 Hello World 项目返回。

一个视图函数,简称视图,是一个简单的 Python 函数,它接受 Web 请求并且返回 Web 响应。响应可以是一张网页的 HTML 内容,一个重定向,一个 404 错误,一个 XML 文档,或者一张图片. . . 是任何东西都可以。无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的 Python 目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为 views.py 的文件中。

这里我们先直接在项目下的 urls.py 文件中写 views 跟 urls,先不分开写了,虽然在 Django 把 views、urls、models、templates 都分别分开来写,其实我们知道这些东西再 Django 里面都是函数、对象等,其实都写到一个文件里面也是可以的。但是真正写项目时应遵循规范,这样写的代码别人也能马上看得懂,容易协作。

重点分析:

  • HttpResponse 模块,它是用来向网页返回内容的,就像 Python 中的 print 一样,只不过 HttpResponse 是把内容显示到网页上。
  • 函数的第一个参数必须是 request,与网页发来的请求有关,request 变量里面包含 get 或 post 的内容,用户浏览器,系统等信息在里面(后面会讲,先了解一下就可以)。
  • urlpatterns 是一个 url 列表,变量名是固定的,不可更改,Django 会匹配这个变量来找 URL。可以去 settings 文件看到 ROOT_URLCONF 参数,已经标明了入口 URL 是那个。
  • url(regex, view, **kwargs, name) 可以接收四个参数,分别是两个必选参数:regex、view;以及两个可选参数:kwargs、name,接下来介绍这四个参数。
    • regex:正则表达式,与之匹配的URL会执行对应的第二个参数 view。
    • view:用于执行与正则表达式匹配的 URL 请求,注意这里是一个对象而不是执行函数。
    • kwargs:视图使用的字典类型的参数。
    • name:用来定义 URL 别名的,可以通过这个别名反解析 URL。
  • regex 匹配时的前后 / 号,比如 “r^hello/$” 不能写成 “r^/hello/$” 这样的,前面的/必须不能写,不然会报错,因为 Django 默认已经帮我们带有。而后面的 / 就有点逻辑了,带上/时,如果我们访问 “http://url/hello/” 可以正常访问,但如果访问 “http://url/hello” 会自动跳转到 “http://url/hello/” 进行访问,这是 Django 帮我们做的。如果不带 / 时,我们访问 “http://url/hello/” 就会报错,而访问 “http://url/hello” 正常。一般都带上即可。

三、Django 创建应用

  • 创建投票 App

要先进入项目目录下,cd project_name 然后执行下面的命令。

一般一个项目有多个 app,当然通用的 app 也可以在多个项目中使用。与项目名类似 app name 也需要为合法的 Python 包名,如 blog,news, aboutus 等都是合法的 app 名称。

__init__.py:用于说明 app_name 目录是一个 Python 模块。

admin.py:新建 App 时会自动创建 admin,当需要使用后台来管理这个 App 时就可以在这个文件中设置。

apps.py:这个模块是新版本才添加的,就是一个 App 的配置文件,里面内容不多。

migrations:这个模块是新版才添加的,用来做数据库迁移的,当我们使用 ORM 创建了表结构之后,就会应用到数据库的,但是当我们对表结构做变更之后,在 Django 1.6 之前是没法再次应用的。有了这个模块之后,当我们对表结构做更改之后,执行几个命令就可以把新的结构应用到数据库,老数据不会丢失。

models.py:包含一系列的模型类,每个模型类对应数据库中的一个表,这之间的映射由 Django 来做,有关数据库的配置在 project_name/settings.py 中,另外只有 App 才能使用 model,而项目不行。

tests.py:可以用来写单元测试使用。

views.py:包含的是对各个请求的处理逻辑,前面说的 URL Dispacher 即将 URL 请求映射到这个文件中的函数或类方法上。同时可以在 polls 目录下创建 template 目录,然后将前台的 html,css,script 等内容放置在这个目录下,并在 setttings.py 文件添加相应的配置信息。所以,我们其实可以看到 App 相当于一个相对独立的功能模块,其遵循的设计理念是 MVT(类似 MVC);在一个大型的项目中,可以包含很多 App,而且每个 App 可以在不同的项目中复用,这也符合 Django 的编程理念,即:不要做重复的事情。

综上所述,Project 和 App 的区别已经很明显了,Project 包含一些全局配置,这些配置构成一个全局的运行平台,各个 App 都运行在这个全局的运行平台上,而 App 代表的是一个相对独立的功能模块,所以程序的逻辑都在 App 中。一个 Project 一般包含多个 App,一个 App 也可以用在多个 Project中。

App 的设计是可插拔的,其不一定非得在 Project 目录下,但是需要在 settings 文件中设置好,如下:

上面的 admin、auth、sessions 等应用都是内置定义好的,如果有新的应用只需要添加即可。

  • 配置项目导入App

要在我们的项目中包含该应用程序,我们需要在INSTALLED_APPS设置中添加对其配置类的引用。 PollsConfig类位于polls/apps.py文件中,因此其点分路径为’polls.apps.PollsConfig’。编辑settings.py文件,并将点分路径添加到INSTALLED_APPS设置。看起来像下面这样:

官方推荐写“polls.apps.PollsConfig”这种格式,直接写“polls”也是可以的。

另外,请注意INSTALLED_APPS设置。它保存这个Django实例中激活的所有的Django应用的名字。应用可以在多个项目中使用,而且你可以将这些应用打包和分发给其他人在他们的项目中使用。默认情况下,INSTALLED_APPS包含下面的应用,它们都是Django默认的:

django.contrib.admin —— 后台管理站点,你会很快使用它。

django.contrib.auth —— 认证系统。

django.contrib.contenttypes —— 用于内容类型的框架。

django.contrib.sessions —— 会话框架。

django.contrib.messages —— 消息框架。

django.contrib.staticfiles —— 管理静态文件的框架。

这些应用,默认包含在Django中,以方便通用场合下使用。

  • 编写App View

前面我们写了一个Hello world项目,是在Project下面编写的,并且都写在了urls.py文件中。下面我们就按照Django规范写法,把各个模块都分开写,业务逻辑都应该在App中views.py中实现(注意把urls.py文件还原)。

  • 编写URL

在App中把view写好之后,就可以回到Project中编写url了。

然后可以使用curl访问了,结果如下:

但是这样有一个缺点,就是当App多了的时候,Project里面的配置就会让你眼花缭乱,并且如果不同项目有同名函数,在import时可能都需要使用as关键字做个别名才可以运行。对于这个问题Django也给出了处理办法,就是各自App的url自行处理,然后只需要使用include包含进Project的urls.py文件即可。这样,Project只管项目配置,不管App。

此时,更改Project的urls.py文件,如下:

然后,我们需要在App目录下创建urls.py文件,如下:

需要注意的一点是,经过Project匹配之后的URL转到App中之后,App中的url正则写成“^$”了,而不是“^polls/$”,因为App的url匹配的是Project中匹配到的路径之后的。比如你访问路径是“http://URL/polls/new”,那么经过Project的“^polls/”匹配之后,到App后只能去匹配“new”了,而不是“/polls/new”。一定不要搞混这里,这也是Django的设计理念,就是在Project层已经匹配过了,再到App层如果匹配同样的路径也没有意义。

四、视图与URL进阶

上面已经简单演示了视图与URL相关操作,但都是静态的。下面再学习一下带参数的视图与URL,在网页上做加减法。

首先采用/polls/?a=100&b=200这样的GET方法进行加法操作,各个文件配置如下:

注:request.GET获取到的是一个QueryDict,类似于一个字典,更好的办法是用request.GET.get(‘a’, 0) ,当a不存在时给一个默认值0。这里我们打印出了GET获取到的类字典,后面可以看到。

都修改完成后,可以选择重启webserver,正常运行的情况下,就可以访问了。

如果直接访问:http://10.10.0.109:8000/polls/ ,就会出现MultiValueDictKeyError错误。这是因为我们并没有传值进去,我们在后面加上?a=100&b=200 ,即访问http://10.10.0.109:8000/polls/?a=100&b=200

Django视图与URL

网页显示就是a+b的结果,对于a和b可以随意改变其值。其实request对象传递进来的,因为我们是GET请求,所以通过request.GET方法获取到了一个类字典。类型如下:

所以我们使用GET对象request.GET[‘a’]直接可以获取到值,但最好使用request.GET.get(‘a’, 0)标准方式,通过GET对象的get方法获取列表中的第一个值。关于request对象可以看Django写一个简单投票系统

另外,也可以采用/polls/100/200/这样的URL方式,前面介绍的时候就说过Django支持优雅的URL。接着修改文件,再新定义一个add1函数:

我们可以看到url函数中多了“(\d+)”,正则表达式中“\d”代表一个数字,“+”代表一个或多个前面的字符,写在一起“\d+”就是一个或多个数字,用括号括起来的意思是保存为一个子组(更多知识请参见Python正则表达式),每一个子组将作为一个参数,被views.py中的对应视图函数接收。多个数字使用“([0-9]+)”表示也一样。

另外需要说明一点的是,Django从URL中捕获到的参数永远是string类型的,不管你输入的是数值还是字符。所以如果需要其它类型,需要自己接收时转换,比如上面我们把接收到的参数转换为int类型。

我们再访问http://10.10.0.109:8000/polls/100/200/就可以看到和刚才同样的效果,但是这回网址更优雅了。

Django视图与URL

五、URL反解析

在上面的urls.py文件中我们使用到了url函数的name参数,如下:

这里的name=’plus’是用来干什么的呢?

简单说,name可以用于在templates, models, views ……中得到对应的网址,相当于“给网址取了个名字”,只要这个名字不变,网址变了也能通过名字获取到。我们称之为“URL反解析”。

比如我们在开发的时候,刚开始想用的是/polls/100/200/ ,后台发现这样不好,比如我们又想改成/plus/100/200/这样的形式,但是我们在网页中,代码中很多地方都写的是/polls/100/200/这样的形式,这样就导致我们在每个地方都要改,修改网址的代价很大。

有没有更优雅的方式来解决这个问题呢?当然答案是肯定的。我们先说一下如何用Python代码获取对应的网址:

reverse函数接收url中的name值作为第一个参数,后面可以通过args=(参数1,参数2)来传入参数,拼装成一个URL。我们在代码中就可以通过reverse()来获取对应的网址(这个网址可以用来跳转,也可以用来计算相关页面的地址),只要对应的url的name不改,就不用改代码中的网址。

在Django模板中使用也是一样,可以很方便的使用:

不带参数的:{% url ‘name’ %}

带参数的,参数可以是变量名:{% url ‘name’ 参数 %}

例如:<a href=”{% url ‘plus’ 100 200 %}”>link</a>,这样就可以通过{% url ‘plus’ 100 200 %} 获取到对应的网址/plus/100/200/。

开始可能觉得直接写网址简单,但是用多了你一定会发现,用“死网址”的方法很糟糕。

六、URL命名空间

知道了URL反解析之后,又可以考虑另外一个问题了,那就是如果多个App使用同样的一个name值怎么办呢?此时反解析时就不知道找哪个name。所以Django又为我们设计了URL命名空间的概念。

对于URL命名空间有两种级别,一种是App级别的命名空间,一种是Instance级别的命名空间。这里就简单说一下App级别的命名空间,处理方法也很简单,在urls.py文件中定义一个变量即可:

或者写成下面这种形式:

那么在使用反解析时就得带上命名空间了,不然就会报错的:

同理,在模板中也得改,所以最好一开始都定义好App namespace,免得日后需要更改。

对于instance namespace一般用的不多,只有在你的App有多个include时则使用instance namespace(在urls中同一个App默认只能由一个include)。设置方法如下:

本文跟随这个官方教程来学习:http://python.usyiyi.cn/translate/Django_111/intro/index.html


如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (1)
[资助本站您就扫码 谢谢]
分享 (0)

您必须 登录 才能发表评论!