第 20 章 设置应用程序的样式并对其进行部署

第 20 章 设置应用程序的样式并对其进行部署 - 图1

当前,项目“学习笔记”功能已齐备,但未设置样式,也只是在本地计算机上运行。在本章中,我们将以简单而专业的方式设置这个项目的样式,再将其部署到一台服务器上,让世界上的任何人都能够建立账户。

为设置样式,我们将使用Bootstrap库,这是一组工具,用于为Web应用程序设置样式,使其在任何现代设备上都看起来很专业,无论是大型的平板显示器还是智能手机。为此,我们将使用应用程序django-bootstrap3,这也让你能够练习使用其他Django开发人员开发的应用程序。

我们将把项目“学习笔记”部署到Heroku,这个网站让你能够将项目推送到其服务器,让任何有网络连接的人都可使用它。我们还将使用版本控制系统Git来跟踪对这个项目所做的修改。

完成项目“学习笔记”后,你将能够开发简单的Web应用程序,让它们看起来很漂亮,再将它们部署到服务器。你还能够利用更高级的学习资源来提高技能。

20.1 设置项目“学习笔记”的样式

我们一直专注于项目“学习笔记”的功能,而没有考虑样式设置的问题,这是有意为之的。这是一种不错的开发方法,因为能正确运行的应用程序才是有用的。当然,应用程序能够正确运行后,外观就显得很重要了,因为漂亮的应用程序才能吸引用户使用它。

在本节中,我将简要地介绍应用程序django-bootstrap3,并演示如何将其继承到项目中,为部署项目做好准备。

20.1.1 应用程序django-bootstrap3

我们将使用django-bootstrap3来将Bootstrap继承到项目中。这个应用程序下载必要的Bootstrap文件,将它们放到项目的合适位置,让你能够在项目的模板中使用样式设置指令。

为安装django-bootstrap3,在活动的虚拟环境中执行如下命令:

  1. (ll_env)learning_log$ pip install django-bootstrap3
  2. --snip--
  3. Successfully installed django-bootstrap3

接下来,需要在settings.py的INSTALLED_APPS中添加如下代码,在项目中包含应用程序django-boostrap3:

settings.py

  1. --snip--
  2. INSTALLED_APPS = (
  3. --snip--
  4. 'django.contrib.staticfiles',
  5. # 第三方应用程序
  6. 'bootstrap3',
  7. # 我的应用程序
  8. 'learning_logs',
  9. 'users',
  10. )
  11. --snip--

新建一个用于指定其他开发人员开发的应用程序的片段,将其命名为“第三方应用程序”,并在其中添加'bootstrap3'。大多数应用程序都需要包含在INSTALLED_APPS中,为确定这一点,请阅读要使用的应用程序的设置说明。

我们需要让django-bootstrap3包含jQuery,这是一个JavaScript库,让你能够使用Bootstrap模板提供的一些交互式元素。请在settings.py的末尾添加如下代码:

settings.py

  1. --snip--
  2. # 我的设置
  3. LOGIN_URL = 'userslogin/'
  4. # django-bootstrap3的设置
  5. BOOTSTRAP3 = {
  6. 'include_jquery': True,
  7. }

这些代码让你无需手工下载jQuery并将其放到正确的地方。

20.1.2 使用Bootstrap来设置项目“学习笔记”的样式

Bootstrap基本上就是一个大型的样式设置工具集,它还提供了大量的模板,你可将它们应用于项目以创建独特的总体风格。对Bootstrap初学者来说,这些模板比各个样式设置工具使用起来要容易得多。要查看Bootstrap提供的模板,可访问http://getbootstrap.com/,单击Getting Started,再向下滚动到Examples部分,并找到Navbars in action。我们将使用模板Static top navbar,它提供了简单的顶部导航条、页面标题和用于放置页面内容的容器。

图20-1显示了对base.html应用这个Bootstrap模板并对index.html做细微修改后的主页。

{%}

图20-1 项目“学习笔记”的主页——使用Bootstrap设置样式后

知道要获得的效果后,接下来的内容理解起来将更容易。

20.1.3 修改base.html

我们需要修改模板base.html,以使用前述Bootstrap模板。我们把新的base.html分成几个部分进行介绍。

1. 定义HTML头部

对base.html所做的第一项修改是,在这个文件中定义HTML头部,使得显示“学习笔记”的每个页面时,浏览器标题栏都显示这个网站的名称。我们还将添加一些在模板中使用Bootstrap所需的信息。删除base.html的全部代码,并输入下面的代码:

base.html

  1. {% load bootstrap3 %}
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="utf-8">
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  7. <meta name="viewport" content="width=device-width, initial-scale=1">
  8. <title>Learning Log</title>
  9. {% bootstrap_css %}
  10. {% bootstrap_javascript %}
  11. </head>

在❶处,我们加载了django-bootstrap3中的模板标签集。接下来,我们将这个文件声明为使用英语(见❸)编写的HTML文档(见❷)。HTML文件分为两个主要部分:头部(head)和主体(body);在这个文件中,头部始于❹处。HTML文件的头部不包含任何内容:它只是将正确显示页面所需的信息告诉浏览器。在❺处,我们包含了一个title元素,在浏览器中打开网站“学习笔记”的页面时,浏览器的标题栏将显示该元素的内容。

在❻处,我们使用了django-bootstrap3的一个自定义模板标签,它让Django包含所有的Bootstrap样式文件。接下来的标签启用你可能在页面中使用的所有交互式行为,如可折叠的导航栏。❼处为结束标签

2. 定义导航栏

下面来定义页面顶部的导航栏:

  1. --snip--
  2. </head>
  3. <body>
  4. <!-- Static navbar -->
  5. <nav class="navbar navbar-default navbar-static-top">
  6. <div class="container">
  7. <div class="navbar-header">
  8. <button type="button" class="navbar-toggle collapsed"
  9. data-toggle="collapse" data-target="#navbar"
  10. aria-expanded="false" aria-controls="navbar">
  11. </button>
  12. <a class="navbar-brand" href="{% url 'learning_logs:index' %}">
  13. Learning Log</a>
  14. </div>
  15. <div id="navbar" class="navbar-collapse collapse">
  16. <ul class="nav navbar-nav">
  17. <li><a href="{% url 'learning_logs:topics' %}">Topics</a></li>
  18. </ul>
  19. <ul class="nav navbar-nav navbar-right">
  20. {% if user.is_authenticated %}
  21. <li><a>Hello, {{ user.username }}.</a></li>
  22. <li><a href="{% url 'users:logout' %}">log out</a></li>
  23. {% else %}
  24. <li><a href="{% url 'users:register' %}">register</a></li>
  25. <li><a href="{% url 'users:login' %}">log in</a></li>
  26. {% endif %}
  27. </ul>
  28. </div><!--/.nav-collapse -->
  29. </div>
  30. </nav>

第一个元素为起始标签。HTML文件的主体包含用户将在页面上看到的内容。❶处是一个

元素,表示页面的导航链接部分。对于这个元素内的所有内容,都将根据选择器(selector)navbarnavbar-defaultnavbar-static-top定义的Bootstrap样式规则来设置样式。选择器决定了特定样式规则将应用于页面上的哪些元素。

在❷处,这个模板定义了一个按钮,它将在浏览器窗口太窄、无法水平显示整个导航栏时显示出来。如果用户单击这个按钮,将出现一个下拉列表,其中包含所有的导航元素。在用户缩小浏览器窗口或在屏幕较小的移动设备上显示网站时,collapse会使导航栏折叠起来。

在❸处,我们在导航栏的最左边显示项目名,并将其设置为到主页的链接,因为它将出现在这个项目的每个页面中。

在❹处,我们定义了一组让用户能够在网站中导航的链接。导航栏其实就是一个以

    打头的列表(见❺),其中每个链接都是一个列表项(
  • )。要添加更多的链接,可插入更多使用下述结构的行:

    1. <li><a href="{% url 'learning_logs:title' %}">Title</a></li>

    这行表示导航栏中的一个链接。这个链接是直接从base.html的前一个版本中复制而来的。

    在❼处,我们添加了第二个导航链接列表,这里使用的选择器为navbar-right。选择器navbar-right设置一组链接的样式,使其出现在导航栏右边——登录链接和注册链接通常出现在这里。在这里,我们要么显示问候语和注销链接,要么显示注册链接和登录链接。这部分余下的代码结束包含导航栏的元素(见❽)。

    3. 定义页面的主要部分

    base.html的剩余部分包含页面的主要部分:

    1. --snip--
    2. </nav>
    3. <div class="container">
    4. <div class="page-header">
    5. {% block header %}{% endblock header %}
    6. </div>
    7. <div>
    8. {% block content %}{% endblock content %}
    9. </div>
    10. </div> <!-- container -->
    11. <body>
    12. </html>

    ❶处是一个

    起始标签,其class属性为container。div是网页的一部分,可用于任何目的,并可通过边框、元素周围的空间(外边距)、内容和边框之间的间距(内边距)、背景色和其他样式规则来设置其样式。这个div是一个容器,其中包含两个元素:一个新增的名为header的块(见❷)以及我们在第18章使用的content块(见❸)。header块的内容告诉用户页面包含哪些信息以及用户可在页面上执行哪些操作;其class属性值page-header将一系列样式应用于这个块。content块是一个独立的div,未使用class属性指定样式。

    如果你在浏览器中加载“学习笔记”的主页,将看到一个类似于图20-1所示的专业级导航栏。请尝试调整窗口的大小,使其非常窄;此时导航栏将变成一个按钮,如果你单击这个按钮,将打开一个下拉列表,其中包含所有的导航链接。

    注意 这个简化的Bootstrap模板适用于最新的浏览器,而较早的浏览器可能不能正确地渲染某些样式。完整的模板可在http://getbootstrap.com/getting-started/#examples/找到,它几乎在所有浏览器中都管用。

    20.1.4 使用jumbotron设置主页的样式

    下面来使用新定义的header块及另一个名为jumbotron的Bootstrap元素修改主页。jumbotron元素是一个大框,相比于页面的其他部分显得鹤立鸡群,你想在其中包含什么东西都可以;它通常用于在主页中呈现项目的简要描述。我们还可以修改主页显示的消息。index.html的代码如下:

    index.html

    1. {% extends "learning_logs/base.html" %}
    2. {% block header %}
    3. <div class='jumbotron'>
    4. <h1>Track your learning.</h1>
    5. </div>
    6. {% endblock header %}
    7. {% block content %}
    8. <h2>
    9. <a href="{% url 'users:register' %}">Register an account</a> to make
    10. your own Learning Log, and list the topics you're learning about.
    11. </h2>
    12. <h2>
    13. Whenever you learn something new about a topic, make an entry
    14. summarizing what you've learned.
    15. </h2>
    16. {% endblock content %}

    在❶处,我们告诉Django,我们要定义header块包含的内容。在一个jumbotron元素(见❷)中,我们放置了一条简短的标语——Track your Learning,让首次访问者大致知道“学习笔记”是做什么用的。

    在❸处,我们通过添加一些文本,做了更详细的说明。我们邀请用户建立账户,并描述了用户可执行的两种主要操作:添加新主题以及在主题中创建条目。现在的主页类似于图20-1所示,与设置样式前相比,有了很大的改进。

    20.1.5 设置登录页面的样式

    我们改进了登录页面的整体外观,但还未改进登录表单,下面来让表单与页面的其他部分一致:

    login.html

    1. {% extends "learning_logs/base.html" %}
    2. {% load bootstrap3 %}
    3. {% block header %}
    4. <h2>Log in to your account.</h2>
    5. {% endblock header %}
    6. {% block content %}
    7. <form method="post" action="{% url 'users:login' %}" class="form">
    8. {% csrf_token %}
    9. {% bootstrap_form form %}
    10. {% buttons %}
    11. <button name="submit" class="btn btn-primary">log in</button>
    12. {% endbuttons %}
    13. <input type="hidden" name="next" value="{% url 'learning_logs:index' %}" >
    14. <form>
    15. {% endblock content %}

    在❶处,我们在这个模板中加载了bootstrap3模板标签。在❷处,我们定义了header块,它描述了这个页面是做什么用的。注意,我们从这个模板中删除了{% if form.errors %}代码块,因为django-bootstrap3会自动管理表单错误。

    在❸处,我们添加了属性class="form";然后使用模板标签{% bootstrap_form %}来显示表单(见❹);这个标签替换了我们在第19章使用的标签{{ form.as_p }}。模板标签{% booststrap_form %}将Bootstrap样式规则应用于各个表单元素。❺处是bootstrap3起始模板标签{% buttons %},它将Bootstrap样式应用于按钮。

    图20-2显示了现在渲染的登录表单。这个页面比以前整洁得多,其风格一致,用途明确。如果你尝试使用错误的用户名或密码登录,将发现消息的样式与整个网站也是一致的,毫无违和感。

    {%}

    图20-2 使用Bootstrap设置样式后的登录页面

    20.1.6 设置new_topic页面的样式

    下面来让其他网页的风格也一致。首先来修改new_topic页面

    new_topic.html

    1. {% extends "learning_logs/base.html" %}
    2. {% load bootstrap3 %}
    3. {% block header %}
    4. <h2>Add a new topic:</h2>
    5. {% endblock header %}
    6. {% block content %}
    7. <form action="{% url 'learning_logs:new_topic' %}" method='post'
    8. class="form">
    9. {% csrf_token %}
    10. {% bootstrap_form form %}
    11. {% buttons %}
    12. <button name="submit" class="btn btn-primary">add topic</button>
    13. {% endbuttons %}
    14. </form>
    15. {% endblock content %}

    这里的大多数修改都类似于对login.html所做的修改:在❶处加载bootstrap3,添加header块并在其中包含合适的消息;接下来,我们在标签

    中添加属性class="form"(见❷),使用模板标签{% bootstrap_form %}代替{{ form.as_p }}(见❸),并使用bootstrap3结构来定义提交按钮(见❹)。如果你现在登录并导航到new_topic页面,将发现其外观类似于登录页面。

    20.1.7 设置topics页面的样式

    下面来确保用于查看信息的页面的样式也是合适的,首先来设置topics页面的样式:

    topics.html

    1. {% extends "learning_logs/base.html" %}
    2. {% block header %}
    3. <h1>Topics</h1>
    4. {% endblock header %}
    5. {% block content %}
    6. <ul>
    7. {% for topic in topics %}
    8. <li>
    9. <h3>
    10. <a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a>
    11. </h3>
    12. </li>
    13. {% empty %}
    14. <li>No topics have been added yet.</li>
    15. {% endfor %}
    16. </ul>
    17. <h3><a href="{% url 'learning_logs:new_topic' %}">Add new topic</h3>
    18. {% endblock content %}

    我们不需要标签{% load bootstrap3 %},因为我们在这个文件中没有使用任何bootstrap3自定义标签。我们在header块中添加了标题Topics(见❶)。为设置每个主题的样式,我们将它们都设置为

    元素,让它们在页面上显得大些(见❷);对于添加新主题的链接,也做了同样的处理(见❸)。

    20.1.8 设置topic页面中条目的样式

    topic页面包含的内容比其他大部分页面都多,因此需要做的样式设置工作要多些。我们将使用Bootstrap面板(panel)来突出每个条目。面板是一个带预定义样式的div,非常适合用于显示主题的条目:

    topic.html

    1. {% extends 'learning_logs/base.html' %}
    2. {% block header %}
    3. <h2>{{ topic }}</h2>
    4. {% endblock header %}
    5. {% block content %}
    6. <p>
    7. <a href="{% url 'learning_logs:new_entry' topic.id %}">add new entry</a>
    8. </p>
    9. {% for entry in entries %}
    10. <div class="panel panel-default">
    11. <div class="panel-heading">
    12. <h3>
    13. {{ entry.date_added|date:'M d, Y H:i' }}
    14. <small>
    15. <a href="{% url 'learning_logs:edit_entry' entry.id %}">
    16. edit entry</a>
    17. </small>
    18. </h3>
    19. </div>
    20. <div class="panel-body">
    21. {{ entry.text|linebreaks }}
    22. </div>
    23. </div> <!-- panel -->
    24. {% empty %}
    25. There are no entries for this topic yet.
    26. {% endfor %}
    27. {% endblock content %}

    我们首先将主题放在了header块中(见❶)。然后,我们删除了这个模板中以前使用的无序列表结构。在❷处,我们创建了一个面板式div元素(而不是将每个条目作为一个列表项),其中包含两个嵌套的div:一个面板标题(panel-heading)div(见❸)和一个面板主体(panel-body)div(见❹)。其中面板标题div包含条目的创建日期以及用于编辑条目的链接,它们都被设置为

    元素,而对于编辑条目的链接,还使用了标签,使其比时间戳小些(见❺)。

    ❻处是面板主体div,其中包含条目的实际文本。注意,只修改了影响页面外观的元素,对在页面中包含信息的Django代码未做任何修改。

    图20-3显示了修改后的topic页面。“学习笔记”的功能没有任何变化,但显得更专业了,对用户会更有吸引力。

    {%}

    图20-3 使用Bootstrap设置样式后的topic页面

    注意 要使用其他Bootstrap模板,可采用与本章类似的流程:将这个模板复制到base.html中,并修改包含实际内容的元素,以使用该模板来显示项目的信息;然后,使用Bootstrap的样式设置工具来设置各个页面中内容的样式。

    动手试一试

    20-1 其他表单:我们对登录页面和add_topic页面应用了Bootstrap样式。请对其他基于表单的页面做类似的修改:new_entry页面、edit_entry页面和注册页面。

    20-2 设置博客的样式:对于你在第19章创建的项目Blog,使用Bootstrap来设置其样式。

    20.2 部署“学习笔记”

    至此,项目“学习笔记”的外观显得很专业了,下面来将其部署到一台服务器,让任何有网络连接的人都能够使用它。为此,我们将使用Heroku,这是一个基于Web的平台,让你能够管理Web应用程序的部署。我们将让“学习笔记”在Heroku上运行。

    在Windows系统上的部署过程与在Linux和OS X系统上稍有不同。如果你使用的是Windows,请阅读各节的“注意”,它们指出了在Windows系统上需要采取的不同做法。

    20.2.1 建立Heroku账户

    要建立账户,请访问https://heroku.com/,并单击其中的一个注册链接。注册账户是免费的,Heroku提供了免费试用服务,让你能够将项目部署到服务器并对其进行测试。

    注意 Heroku提供的免费试用服务存在一些限制,如可部署的应用程序数量以及用户访问应用程序的频率。但这些限制都很宽松,让你完全能够在不支付任何费用的情况下练习部署应用程序。

    20.2.2 安装Heroku Toolbelt

    要将项目部署到Heroku的服务器并对其进行管理,需要使用Heroku Toolbelt提供的工具。要安装最新的Heroku Toolbelt版本,请访问https://toolbelt.heroku.com/,并根据你使用的操作系统按相关的说明做:使用只包含一行的终端命令,或下载并运行安装程序。

    20.2.3 安装必要的包

    你还需安装很多包,以帮助在服务器上支持Django项目提供的服务。为此,在活动的虚拟环境中执行如下命令:

    1. (ll_env)learning_log$ pip install dj-database-url
    2. (ll_env)learning_log$ pip install dj-static
    3. (ll_env)learning_log$ pip install static3
    4. (ll_env)learning_log$ pip install gunicorn

    务必逐个地执行这些命令,这样你就能知道哪些包未能正确地安装。dj-database-url包帮助Django与Heroku使用的数据库进行通信,dj-staticstatic3包帮助Django正确地管理静态文件,而gunicorn是一个服务器软件,能够在在线环境中支持应用程序提供的服务。(静态文件包括样式规则和JavaScript文件。)

    注意 在Windows系统中,有些必不可少的包可能无法安装,因此如果在你尝试安装有些这样的包时出现错误消息,也不用担心。重要的是让Heroku在部署中安装这些包,下一节就将这样做。

    20.2.4 创建包含包列表的文件requirements.txt

    Heroku需要知道我们的项目依赖于哪些包,因此我们将使用pip来生成一个文件,其中列出了这些包。同样,进入活动虚拟环境,并执行如下命令:

    1. (ll_env)learning_log$ pip freeze > requirements.txt

    命令freeze让pip将项目中当前安装的所有包的名称都写入到文件requirements.txt中。请打开文件requirements.txt,查看项目中安装的包及其版本(如果你使用的是Windows系统,看到的内容可能不全):

    requirements.txt

    1. Django==1.8.4
    2. dj-database-url==0.3.0
    3. dj-static==0.0.6
    4. django-bootstrap3==6.2.2
    5. gunicorn==19.3.0
    6. static3==0.6.1

    “学习笔记”依赖于6个特定版本的包,因此需要在相应的环境中才能正确地运行。我们部署“学习笔记”时,Heroku将安装requirements.txt列出的所有包,从而创建一个环境,其中包含我们在本地使用的所有包。有鉴于此,我们可以信心满满,深信项目部署到Heroku后,行为将与它在本地系统上的完全相同。当你在自己的系统上开发并维护各种项目时,这将是一个巨大的优点。

    接下来,我们需要在包列表中添加psycopg2,它帮助Heroku管理活动数据库。为此,打开文件requirements.txt,并添加代码行psycopg2>=2.6.1。这将安装2.6.1版的psycopg2——如果有更高的版本,则安装更高的版本:

    requirements.txt

    1. Django==1.8.4
    2. dj-database-url==0.3.0
    3. dj-static==0.0.6
    4. django-bootstrap3==6.2.2
    5. gunicorn==19.3.0
    6. static3==0.6.1
    7. psycopg2>=2.6.1

    如果有必不可少的包在你的系统中没有安装,请将其添加到文件requirements.txt中。最终的文件requirements.txt应包含上面列出的每个包。如果在你的系统中,requirements.txt列出的包的版本与上面列出的不同,请保留原来的版本号。

    注意 如果你使用的是Windows系统,请确保文件requirements.txt的内容与前面列出的一致,而不要管你在系统中能够安装哪些包。

    20.2.5 指定Python版本

    如果你没有指定Python版本,Heroku将使用其当前的Python默认版本。下面来确保Heroku使用我们使用的Python版本。为此,在活动的虚拟环境中,执行命令python --version

    1. (ll_env)learning_log$ python --version
    2. Python 3.5.0

    上面的输出表明,我使用的是Python 3.5.0。请在manage.py所在的文件夹中新建一个名为runtime.txt的文件,并在其中输入如下内容:

    runtime.txt

    1. python3.5.0

    这个文件应只包含一行内容,以上面所示的格式指定了你使用的Python版本;请确保输入小写的python,在它后面输入一个连字符,再输入由三部分组成的版本号。

    注意 如果出现错误消息,指出不能使用你指定的Python版本,请访问https://devcenter.heroku.com/并单击Python,再单击链接Specifying a Python Runtime。浏览打开的文章,了解支持的Python版本,并使用与你使用的Python版本最接近的版本。

    20.2.6 为部署到Heroku而修改settings.py

    现在需要在settings.py末尾添加一个片段,在其中指定一些Heroku环境设置:

    settings.py

    1. --snip--
    2. # django-bootstrap3设置
    3. BOOTSTRAP3 = {
    4. 'include_jquery': True,
    5. }
    6. # Heroku设置
    7. if os.getcwd() == 'app':
    8. import dj_database_url
    9. DATABASES = {
    10. 'default': dj_database_url.config(default='postgres:/localhost')
    11. }
    12. # 让request.is_secure()承认X-Forwarded-Proto头
    13. SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
    14. # 支持所有的主机头(host header)
    15. ALLOWED_HOSTS = ['*']
    16. # 静态资产配置
    17. BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    18. STATIC_ROOT = 'staticfiles'
    19. STATICFILES_DIRS = (
    20. os.path.join(BASE_DIR, 'static'),
    21. )

    在❶处,我们使用了函数getcwd(),它获取当前的工作目录(当前运行的文件所在的目录)。在Heroku部署中,这个目录总是/app。在本地部署中,这个目录通常是项目文件夹的名称(就我们的项目而言,为learning_log)。这个if测试确保仅当项目被部署到Heroku时,才运行这个代码块。这种结构让我们能够将同一个设置文件用于本地开发环境和在线服务器。

    在❷处,我们导入了dj_database_url,用于在Heroku上配置服务器。Heroku使用PostgreSQL(也叫Postgres)——一种比SQLite更高级的数据库;这些设置对项目进行配置,使其在Heroku上使用Postgres数据库。其他设置的作用分别如下:支持HTTPS请求(见❸);让Django能够使用Heroku的URL来提供项目提供的服务(见❹);设置项目,使其能够在Heroku上正确地提供静态文件(见❺)。

    20.2.7 创建启动进程的Procfile

    Procfile告诉Heroku启动哪些进程,以便能够正确地提供项目提供的服务。这个文件只包含一行,你应将其命名为Procfile(其中的P为大写),不指定文件扩展名,并保存到manage.py所在的目录中。

    Procfile的内容如下:

    Procfile

    1. web: gunicorn learning_log.wsgi --log-file -

    这行代码让Heroku将gunicorn用作服务器,并使用learning_log/wsgi.py中的设置来启动应用程序。标志log-file告诉Heroku应将哪些类型的事件写入日志。

    20.2.8 为部署到Heroku而修改wsgi.py

    为部署到Heroku,我们还需修改wsgi.py,因为Heroku需要的设置与我们一直在使用的设置稍有不同:

    wsgi.py

    1. --snip--
    2. import os
    3. from django.core.wsgi import get_wsgi_application
    4. from dj_static import Cling
    5. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "learning_log.settings")
    6. application = Cling(get_wsgi_application())

    我们导入了帮助正确地提供静态文件的Cling,并使用它来启动应用程序。这些代码在本地也适用,因此无需将其放在if代码块内。

    20.2.9 创建用于存储静态文件的目录

    在Heroku上,Django搜集所有的静态文件,并将它们放在一个地方,以便能够高效地管理它们。我们将创建一个用于存储这些静态文件的目录。在文件夹learning_log中,有一个名称也为learning_log的子文件夹。在这个子文件夹中,新建一个名为static的文件夹,因此这个文件夹的路径为learning_log/learning_log/static/。我们还需在这个文件夹中创建一个占位文件,因为项目被推送到Heroku时,它将不会包含原来为空的文件夹。在目录static/中,创建一个名为placeholder.txt的文件:

    placeholder.txt

    1. This file ensures that learning_log/static/ will be added to the project.
    2. Django will collect static files and place them in learning_log/static/.

    上述内容没有什么特别之处,只是指出了在项目中添加这个文件的原因。

    20.2.10 在本地使用gunicorn服务器

    如果你使用的是Linux或OS X,可在部署到Heroku前尝试在本地使用gunicorn服务器。为此,在活动的虚拟环境中,执行命令heroku local以启动Procfile指定的进程:

    1. (ll_env)learning_log$ heroku local
    2. Installing Heroku Toolbelt v4... done
    3. --snip--
    4. forego | starting web.1 on port 5000
    5. web.1 | [2015-08-13 22:00:45 -0800] [12875] [INFO] Starting gunicorn 19.3.0
    6. web.1 | [2015-08-13 22:00:45 -0800] [12875] [INFO] Listening at:
    7. http://0.0.0.0:5000 (12875)
    8. web.1 | [2015-08-13 22:00:45 -0800] [12878] [INFO] Booting worker with pid: 12878

    首次执行命令heroku local时,将安装Heroku Toolbelt中的很多包。这里的输出表明启动了gunicorn,其进程id为12875(见❶)。❷处的输出表明,gunicorn在端口5000上侦听请求。另外,gunicorn还启动了一个工作进程(12878),用于帮助处理请求(见❸)。

    为确认一切运行正常,请访问http://localhost:5000/,你将看到“学习笔记”的主页,就像使用Django服务器(runserver)时一样。为停止heroku local启动的进程,请按Ctrl + C,你将在本地开发中继续使用runserver

    注意 gunicorn不能在Windows系统上运行,因此如果你使用的是Windows系统,请跳过这一步。但这不会影响你将项目部署到Heroku。

    20.2.11 使用Git跟踪项目文件

    如果你阅读完了第17章,就知道Git是一个版本控制程序,让你能够在每次成功实现新功能后都拍摄项目代码的快照。无论出现什么问题(如实现新功能时不小心引入了bug),你都可以轻松地恢复到最后一个可行的快照。每个快照都被称为提交

    使用Git意味着你在试着实现新功能时无需担心破坏项目。将项目部署到服务器时,需要确保部署的是可行版本。如果你想更详细地了解Git和版本控制,请参阅附录D。

    1. 安装Git

    Heroku Toolbelt包含Git,因此它应该已经安装到了你的系统中。然而,在安装Heroku Toolbelt之前打开的终端窗口中无法访问Git,因此请打开一个新的终端窗口,并在其中执行命令git --version

    1. (ll_env)learning_log$ git --version
    2. git version 2.5.0

    如果由于某种原因出现了错误消息,请参阅附录D中的Git安装说明。

    2. 配置Git

    Git跟踪谁修改了项目,即便项目由一个人开发时亦如此。为进行跟踪,Git需要知道你的用户名和email。因此,你必须提供用户名,但对于练习项目,可随便伪造一个email:

    1. (ll_env)learning_log$ git config --global user.name "ehmatthes"
    2. (ll_env)learning_log$ git config --global user.email "eric@example.com"

    如果你忘记了这一步,当你首次提交时,Git将提示你提供这些信息。

    3. 忽略文件

    我们无需让Git跟踪项目中的每个文件,因此将让Git忽略一些文件。为此,在manage.py所在的文件夹中创建一个名为.gitignore的文件。注意,这个文件名以句点打头,且不包含扩展名。在这个文件中输入如下内容:

    .gitignore

    1. ll_env/
    2. __pycache__/
    3. *.sqlite3

    我们让Git忽略目录llenv,因为我们随时都可以自动重新创建它。我们还指定不跟踪目录 \pycache_,这个目录包含Django运行.py文件时自动创建的.pyc文件。我们没有跟踪对本地数据库的修改,因为这是一个糟糕的做法:如果你在服务器上使用的是SQLite,当你将项目推送到服务器时,可能会不小心用本地测试数据库覆盖在线数据库。

    注意 如果你使用的是Python 2.7,请将_pycache_替换为*.pyc,因为Python 2.7不会创建目录pycache

    4. 提交项目

    我们需要为“学习笔记”初始化一个Git仓库,将所有必要的文件都加入到这个仓库中,并提交项目的初始状态,如下所示:

    1. (ll_env)learning_log$ git init
    2. Initialized empty Git repository in homeehmatthes/pcc/learning_log/.git/
    3. (ll_env)learning_log$ git add .
    4. (ll_env)learning_log$ git commit -am "Ready for deployment to heroku."
    5. [master (root-commit) dbc1d99] Ready for deployment to heroku.
    6. 43 files changed, 746 insertions(+)
    7. create mode 100644 .gitignore
    8. create mode 100644 Procfile
    9. --snip--
    10. create mode 100644 users/views.py
    11. (ll_env)learning_log$ git status
    12. # On branch master
    13. nothing to commit, working directory clean
    14. (ll_env)learning_log$

    在❶处,我们执行命令git init,在“学习笔记”所在的目录中初始化一个空仓库。在❷处,我们执行了命令git add .(千万别忘了这个句点),它将未被忽略的文件都添加到这个仓库中。在❸处,我们执行了命令git commit -am commit message,其中的标志-a让Git在这个提交中包含所有修改过的文件,而标志-m让Git记录一条日志消息。

    在❹处,我们执行了命令git status,输出表明当前位于分支master中,而工作目录是干净(clean)的。每当你要将项目推送到Heroku时,都希望看到这样的状态。

    20.2.12 推送到Heroku

    我们终于为将项目推送到Heroku做好了准备。在活动的虚拟环境中,执行下面的命令:

    1. (ll_env)learning_log$ heroku login
    2. Enter your Heroku credentials.
    3. Email: eric@example.com
    4. Password (typing will be hidden):
    5. Logged in as eric@example.com
    6. (ll_env)learning_log$ heroku create
    7. Creating afternoon-meadow-2775... done, stack is cedar-14
    8. https://afternoon-meadow-2775.herokuapp.com/ |
    9. https://git.heroku.com/afternoon-meadow-2775.git
    10. Git remote heroku added
    11. (ll_env)learning_log$ git push heroku master
    12. --snip--
    13. remote: -----> Launching... done, v6
    14. remote: https://afternoon-meadow-2775.herokuapp.com/ deployed to Heroku ❹
    15. remote: Verifying deploy.... done.
    16. To https://git.heroku.com/afternoon-meadow-2775.git
    17. bdb2a35..62d711d master -> master
    18. (ll_env)learning_log$

    首先,在终端会话中,使用你在https://heroku.com/创建账户时指定的用户名和密码来登录Heroku(见❶)。然后,让Heroku创建一个空项目(见❷)。Heroku生成的项目名由两个单词和一个数字组成,你以后可修改这个名称。接下来,我们执行命令git push heroku master(见❸),它让Git将项目的分支master推送到Heroku刚才创建的仓库中;Heroku随后使用这些文件在其服务器上创建项目。❹处列出了用于访问这个项目的URL。

    执行这些命令后,项目就部署好了,但还未对其做全面的配置。为核实正确地启动了服务器进程,请执行命令heroku ps

    1. (ll_env)learning_log$ heroku ps
    2. Free quota left: 17h 40m
    3. === web (Free): `gunicorn learning_log.wsgi __log-file -`
    4. web.1: up 2015/08/14 07:08:51 (~ 10m ago)
    5. (ll_env)learning_log$

    输出指出了在接下来的24小时内,项目还可在多长时间内处于活动状态(见❶)。编写本书时,Heroku允许免费部署在24小时内最多可以有18小时处于活动状态。项目的活动时间超过这个限制后,将显示标准的服务器错误页面,稍后我们将设置这个错误页面。在❷处,我们发现启动了Procfile指定的进程。

    现在,我们可以使用命令heroku open在浏览器中打开这个应用程序了:

    1. (ll_env)learning_log$ heroku open
    2. Opening afternoon-meadow-2775... done

    你也可以启动浏览器并输入Heroku告诉你的URL,但上述命令可实现同样的结果。你将看到“学习笔记”的主页,其样式设置正确无误,但你还无法使用这个应用程序,因为我们还没有建立数据库。

    注意 部署到Heroku的流程会不断变化。如果你遇到无法解决的问题,请通过查看Heroku文档来获取帮助。为此,可访问https://devcenter.heroku.com/,单击Python,再单击链接Getting Started with Django。如果你看不懂这些文档,请参阅附录C提供的建议。

    20.2.13 在Heroku上建立数据库

    为建立在线数据库,我们需要再次执行命令migrate,并应用在开发期间生成的所有迁移。要对Heroku项目执行Django和Python命令,可使用命令heroku run。下面演示了如何对Heroku部署执行命令migrate

    1. (ll_env)learning_log$ heroku run python manage.py migrate
    2. Running `python manage.py migrate` on afternoon-meadow-2775... up, run.2435
    3. --snip--
    4. Running migrations:
    5. --snip--
    6. Applying learning_logs.0001_initial... OK
    7. Applying learning_logs.0002_entry... OK
    8. Applying learning_logs.0003_topic_user... OK
    9. Applying sessions.0001_initial... OK
    10. (ll_env)learning_log$

    我们首先执行了命令heroku run python manage.py migrate(见❶);Heroku随后创建一个终端会话来执行命令migrate(见❷)。在❸处,Django应用默认迁移以及我们在开发“学习笔记”期间生成的迁移。

    现在如果你访问这个部署的应用程序,将能够像在本地系统上一样使用它。然而,你看不到你在本地部署中输入的任何数据,因为它们没有复制到在线服务器。一种通常的做法是不将本地数据复制到在线部署中,因为本地数据通常是测试数据。

    你可以分享“学习笔记”的Heroku URL,让任何人都可以使用它。在下一节,我们将再完成几个任务,以结束部署过程并让你能够继续开发“学习笔记”。

    20.2.14 改进Heroku部署

    在本节中,我们将通过创建超级用户来改进部署,就像在本地一样。我们还将让这个项目更安全:将DEBUG设置为False,让用户在错误消息中看不到额外的信息,以防他们使用这些信息来攻击服务器。

    1. 在Heroku上创建超级用户

    我们知道可使用命令heroku run来执行一次性命令,但也可这样执行命令:在连接到了Heroku服务器的情况下,使用命令heroku run bash来打开Bash终端会话。Bash是众多Linux终端运行的语言。我们将使用Bash终端会话来创建超级用户,以便能够访问在线应用程序的管理网站:

    1. (ll_env)learning_log$ heroku run bash
    2. Running `bash` on afternoon-meadow-2775... up, run.6244
    3. ~ $ ls
    4. learning_log learning_logs manage.py Procfile requirements.txt runtime.txt users
    5. staticfiles
    6. ~ $ python manage.py createsuperuser
    7. Username (leave blank to use 'u41907'): ll_admin
    8. Email address:
    9. Password:
    10. Password (again):
    11. Superuser created successfully.
    12. ~ $ exit
    13. exit
    14. (ll_env)learning_log$

    在❶处,我们执行命令ls,以查看服务器上有哪些文件和目录;服务器包含的文件和目录应该与本地系统相同。你可以像遍历其他文件系统一样遍历这个文件系统。

    注意 即便你使用的是Windows系统,也应使用这里列出的命令(如ls而不是dir),因为你正通过远程连接运行一个Linux终端。

    在❷处,我们执行了创建超级用户的命令,它像第18章在本地系统创建超级用户一样提示你输入相关的信息。在这个终端会话中创建超级用户后,使用命令exit返回到本地系统的终端会话(见❸)。

    现在,你可以在在线应用程序的URL末尾添加/admin/来登录管理网站了。对我而言,这个URL为https://afternoon-meadow-2775.herokuapp.com/admin/

    如果已经有其他人开始使用这个项目,别忘了你可以访问他们的所有数据!千万别不把这当回事,否则用户就不会再将其数据托付给你了。

    2. 在Heroku上创建对用户友好的URL

    你可能希望URL更友好,比https://afternoon-meadow-2775.herokuapp.com/更好记。为此,可只需使用一个命令来重命名应用程序:

    1. (ll_env)learning_log$ heroku apps:rename learning-log
    2. Renaming afternoon-meadow-2775 to learning-log... done
    3. https://learning-log.herokuapp.com/ | https://git.heroku.com/learning-log.git
    4. Git remote heroku updated
    5. (ll_env)learning_log$

    给应用程序命名时,可使用字母、数字和连字符;你想怎么命名应用程序都可以,只要指定的名称未被别人使用就行。现在,项目的URL变成了https://learning-log.herokuapp.com/;使用以前的URL再也无法访问它,命令apps:rename将整个项目都移到了新的URL处。

    注意 你使用Heroku提供的免费服务来部署项目时,如果项目在指定的时间内未收到请求或过于活跃,Heroku将让项目进入休眠状态。用户初次访问处于休眠状态的网站时,加载时间将更长,但对于后续请求,服务器的响应速度将更快。这就是Heroku能够提供免费部署的原因所在。

    20.2.15 确保项目的安全

    当前,我们部署的项目存在一个严重的安全问题:settings.py包含设置DEBUG=True,它在发生错误时显示调试信息。开发项目时,Django的错误页面向你显示了重要的调试信息,如果将项目部署到服务器后依然保留这个设置,将给攻击者提供大量可供利用的信息。我们还需确保任何人都无法看到这些信息,也不能冒充项目托管网站来重定向请求。

    下面来修改settings.py,以让我们能够在本地看到错误消息,但部署到服务器后不显示任何错误消息:

    settings.py

    1. --snip--
    2. # Heroku设置
    3. if os.getcwd() == '/app':
    4. --snip--
    5. # 让request.is_secure()承认X-Forwarded-Proto头
    6. SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
    7. # 只允许Heroku托管这个项目
    8. ALLOWED_HOSTS = ['learning-log.herokuapp.com']
    9. DEBUG = False
    10. # 静态资产配置
    11. --snip--

    我们只需做两方面的修改。在❶处,修改ALLOWED_HOSTS,只允许Heroku托管这个项目。你需要使用应用程序的名称,可以是Heroku提供的名称(如afternoon-meadow-2775.herokuapp.com),也可以是你选择的名称。在❷处,我们将DEBUG设置为False,让Django不在错误发生时显示敏感信息。

    20.2.16 提交并推送修改

    现在需要将对settings.py所做的修改提交到Git仓库,再将修改推送到Heroku。下面的终端会话演示了这个过程:

    1. (ll_env)learning_log$ git commit -am "Set DEBUG=False for Heroku."
    2. [master 081f635] Set DEBUG=False for Heroku.
    3. 1 file changed, 4 insertions(+), 2 deletions(-)
    4. (ll_env)learning_log$ git status
    5. # On branch master
    6. nothing to commit, working directory clean
    7. (ll_env)learning_log$

    我们执行命令git commit,并指定了一条简短而具有描述性的提交消息(见❶)。别忘了,标志-am让Git提交所有修改过的文件,并记录一条日志消息。Git找出唯一一个修改过的文件,并将所做的修改提交到仓库。

    ❷处显示的状态表明我们在仓库的分支master上工作,当前没有任何未提交的修改。推送到Heroku之前,必须检查状态并看到刚才所说的消息。如果你没有看到这样的消息,说明有未提交的修改,而这些修改将不会推送到服务器。在这种情况下,可尝试再次执行命令commit,但如果你不知道该如何解决这个问题,请阅读附录D,更深入地了解Git的用法。

    下面来将修改后的仓库推送到Heroku:

    1. (ll_env)learning_log$ git push heroku master
    2. --snip--
    3. remote: -----> Python app detected
    4. remote: -----> Installing dependencies with pip
    5. --snip--
    6. remote: -----> Launching... done, v8
    7. remote: https://learning-log.herokuapp.com/ deployed to Heroku
    8. remote: Verifying deploy.... done.
    9. To https://git.heroku.com/learning-log.git
    10. 4c9d111..ef65d2b master -> master
    11. (ll_env)learning_log$

    Heroku发现仓库发生了变化,因此重建项目,确保所有的修改都已生效。它不会重建数据库,因此这次无需执行命令migrate

    现在要核实部署更安全了,请输入项目的URL,并在末尾加上我们未定义的扩展。例如,尝试访问http://learning-log.herokuapp.com/letmein/。你将看到一个通用的错误页面,它没有泄露任何有关该项目的具体信息。如果你尝试向本地的“学习笔记”发出同样的请求——输入URL http://localhost:8000/letmein/,你将看到完整的Django错误页面。这样的结果非常理想,你接着开发这个项目时,将看到信息丰富的错误消息,但用户看不到有关项目代码的重要信息。

    20.2.17 创建自定义错误页面

    在第19章,我们对“学习笔记”进行了配置,使其在用户请求不属于他的主题或条目时返回404错误。你可能还遇到过一些500错误(内部错误)。404错误通常意味着你的Django代码是正确的,但请求的对象不存在。500错误通常意味着你编写的代码有问题,如views.py中的函数有问题。当前,在这两种情况下,Django都返回通用的错误页面,但我们可以编写外观与“学习笔记”一致的404和500错误页面模板。这些模板必须放在根模板目录中。

    1. 创建自定义模板

    在文件夹learning_log/learning_log中,新建一个文件夹,并将其命名为templates;再在这个文件夹中新建一个名为404.html的文件,并在其中输入如下内容:

    404.html

    1. {% extends "learning_logs/base.html" %}
    2. {% block header %}
    3. <h2>The item you requested is not available. (404)</h2>
    4. {% endblock header %}

    这个简单的模板指定了通用的404错误页面包含的信息,并且该页面的外观与网站的其他部分一致。

    再创建一个名为500.html的文件,并在其中输入如下代码:

    500.html

    1. {% extends "learning_logs/base.html" %}
    2. {% block header %}
    3. <h2>There has been an internal error. (500)</h2>
    4. {% endblock header %}

    这些新文件要求对settings.py做细微的修改:

    settings.py

    1. --snip--
    2. TEMPLATES = [
    3. {
    4. 'BACKEND': 'django.template.backends.django.DjangoTemplates',
    5. 'DIRS': [os.path.join(BASE_DIR, 'learning_log/templates')],
    6. 'APP_DIRS': True,
    7. --snip--
    8. },
    9. ]
    10. --snip--

    这项修改让Django在根模板目录中查找错误页面模板。

    2. 在本地查看错误页面

    在将项目推送到Heroku之前,如果你要在本地查看错误页面是什么样的,首先需要在本地设置中设置Debug=False,以禁止显示默认的Django调试页面。为此,可对settings.py做如下修改(请确保你修改的是用于本地环境的settings.py部分,而不是用于Heroku的部分):

    settings.py

    1. --snip--
    2. # 安全警告:不要在在线环境中启用调试!
    3. DEBUG = False
    4. ALLOWED_HOSTS = ['localhost']
    5. --snip--

    DEBUG被设置为False时,你必须在ALLOWED_HOSTS中指定一个主机。现在,请求一个不属于你的主题或条目,以查看404错误页面;请求不存在的URL(如localhost:8000/letmein/),以查看500错误页面。

    查看错误页面后,将DEBUG重新设置为True,以方便你进一步开发“学习笔记”。(在settings.py中用于Heroku部署的部分中,确保DEBUG依然被设置为False)。

    注意 500错误页面不会显示任何有关当前用户的信息,因为发生服务器错误时,Django不会通过响应发送任何上下文信息。

    3. 将修改推送到Heroku

    现在需要提交对模板所做的修改,并将这些修改推送到Heroku:

    1. (ll_env)learning_log$ git add .
    2. (ll_env)learning_log$ git commit -am "Added custom 404 and 500 error pages."
    3. 3 files changed, 15 insertions(+), 10 deletions(-)
    4. create mode 100644 learning_log/templates/404.html
    5. create mode 100644 learning_log/templates/500.html
    6. (ll_env)learning_log$ git push heroku master
    7. --snip--
    8. remote: Verifying deploy.... done.
    9. To https://git.heroku.com/learning-log.git
    10. 2b34ca1..a64d8d3 master -> master
    11. (ll_env)learning_log$

    在❶处,我们执行了命令git add,这是因为我们在项目中创建了一些新文件,因此需要让Git跟踪这些文件。然后,我们提交所做的修改(见❷),并将修改后的项目推送到Heroku(见❸)。

    现在,错误页面出现时,其样式应该与网站的其他部分一致,这样在发生错误时,用户将不会感到突兀。

    4. 使用方法get_object_or_404()

    现在,如果用户手工请求不存在的主题或条目,将导致500错误。Django尝试渲染请求的页面,但没有足够的信息来完成这项任务,进而引发500错误。对于这种情形,将其视为404错误更合适,为此可使用Django快捷函数get_object_or_404()。这个函数尝试从数据库获取请求的对象,如果这个对象不存在,就引发404异常。我们在views.py中导入这个函数,并用它替换函数get()

    views.py

    1. --snip--
    2. from django.shortcuts import render, get_object_or_404
    3. from django.http import HttpResponseRedirect, Http404
    4. --snip--
    5. @login_required
    6. def topic(request, topic_id):
    7. """显示单个主题及其所有的条目"""
    8. topic = get_object_or_404(Topic, id=topic_id)
    9. # 确定主题属于当前用户
    10. --snip--

    现在,如果你请求不存在的主题(例如,使用URL http://localhost:8000/topics/999999/),将看到404错误页面。为部署这里所做的修改,再次提交,并将项目推送到Heroku。

    20.2.18 继续开发

    将项目“学习笔记”推送到服务器后,你可能想进一步开发它或开发要部署的其他项目。更新项目的过程几乎完全相同。

    首先,你对本地项目做必要的修改。如果在修改过程中创建了新文件,使用命令git add .(千万别忘记这个命令末尾的句点)将它们加入到Git仓库中。如果有修改要求迁移数据库,也需要执行这个命令,因为每个迁移都将生成新的迁移文件。

    然后,使用命令git commit -am "commit message"将修改提交到仓库,再使用命令git push heroku master将修改推送到Heroku。如果你在本地迁移了数据库,也需要迁移在线数据库。为此,你可以使用一次性命令heroku run python manage.py migrate,也可使用heroku run bash打开一个远程终端会话,并在其中执行命令python manage.py migrate。然后访问在线项目,确认你期望看到的修改已生效。

    在这个过程中很容易犯错,因此看到错误时不要大惊小怪。如果代码不能正确地工作,请重新审视所做的工作,尝试找出其中的错误。如果找不出错误,或者不知道如何撤销错误,请参阅附录C中有关如何寻求帮助的建议。不要羞于去寻求帮助:每个学习开发项目的人都可能遇到过你面临的问题,因此总有人乐意伸出援手。通过解决遇到的每个问题,可让你的技能稳步提高,最终能够开发可靠而有意义的项目,还能解决别人遇到的问题。

    20.2.19 设置SECRET_KEY

    Django根据settings.py中设置SECRET_KEY的值来实现大量的安全协议。在这个项目中,我们提交到仓库的设置文件包含设置SECRET_KEY。对于一个练习项目而言,这足够了,但对于生产网站,应更细致地处理设置SECRET_KEY。如果你创建的项目的用途很重要,务必研究如何更安全地处理设置SECRET_KEY

    20.2.20 将项目从Heroku删除

    一个不错的练习是,使用同一个项目或一系列小项目执行部署过程多次,直到对部署过程了如指掌。然而,你需要知道如何删除部署的项目。Heroku可能还限制了你可免费托管的项目数,另外,你也不希望让自己的账户中塞满大量的练习项目。

    在Heroku网站(https://heroku.com/)登录后,你将被重定向到一个页面,其中列出了你托管的所有项目。单击要删除的项目,你将看到另一个页面,其中显示了有关这个项目的信息。单击链接Settings,再向下滚动,找到用于删除项目的链接并单击它。这种操作是不可撤销的,因此Heroku让你手工输入要删除的项目的名称,以确认你确实要删除它。

    如果你喜欢在终端中工作,也可使用命令destroy来删除项目:

    1. (ll_env)learning_log$ heroku apps:destroy --app appname

    其中appname是要删除的项目的名称,可能类似于afternoon-meadow-2775,也可能类似于learning-log(如果你重命名了项目)。你将被要求再次输入项目名,以确认你确实要删除它。

    注意 删除Heroku上的项目对本地项目没有任何影响。如果没有人使用你部署的项目,就尽管去练习部署过程好了,在Heroku删除项目再重新部署完全合情合理。

    动手试一试

    20-3 在线博客:将你一直在开发的项目Blog部署到Heroku。确保将DEBUG设置为False,并修改设置ALLOWED_HOSTS,让部署相当安全。

    20-4 在更多的情况下显示404错误页面:在视图函数new_entry()edit_entry()中,也使用函数get_object_or_404()。完成这些修改后进行测试:输入类似于http://localhost:8000/new_entry/99999/的URL,确认你能够看到404错误页面。

    20-5 扩展“学习笔记”:在“学习笔记”中添加一项功能,将修改推送到在线部署。尝试做一项简单的修改,如在主页中对项目作更详细的描述;再尝试添加一项更高级的功能,如让用户能够将主题设置为公开的。为此,需要在模型Topic中添加一个名为public的属性(其默认值为False),并在new_topic页面中添加一个表单元素,让用户能够将私有主题改为公开的。然后,你需要迁移项目,并修改views.py,让未登录的用户也可以看到所有公开的主题。将修改推送到Heroku后,别忘了迁移在线数据库。

    20.3 小结

    在本章中,你学习了如何使用Bootstrap库和应用程序django-bootstrap3赋予应用程序简单而专业的外观。使用Bootstrap意味着无论用户使用哪种设备来访问你的项目,你选择的样式都将实现几乎相同的效果。

    你学习了Bootstrap的模板,并使用模板Static top navbar赋予了“学习笔记”简单的外观。你学习了如何使用jumbotron来突出主页中的消息,还学习了如何给网站的所有网页设置一致的样式。

    在本章的最后一部分,你学习了如何将项目部署到Heroku的服务器,让任何人都能够访问它。你创建了一个Heroku账户,并安装了一些帮助管理部署过程的工具。你使用Git将能够正确运行的项目提交到一个仓库,再将这个仓库推送到Heroku的服务器。最后,你将DEBUG设置为False,以确保在线服务器上应用程序的安全。

    至此,开发完了项目“学习笔记”后,你可以自己动手开发项目了。请先让项目尽可能简单,确定它能正确运行后,再添加复杂的功能。愿你学习愉快,开发项目时有好运相伴!