Python學習之路19-設定應用程式的樣式並對其進行部署

VPointer發表於2018-05-29

《Python程式設計:從入門到實踐》筆記。

本篇將對Django專案做最後的完善。本篇也是這本書的最後一篇。

1. 前言

在本篇中,我們將:

  • 使用Bootstrap庫設定樣式;
  • 把專案部署到Heroku上。

2. 設定專案“學習筆記”的樣式

之前關注的都是專案的功能,現在來為專案新增樣式。

我們將使用django-bootstrap3來設定樣式。首先請在虛擬環境中安裝這個第三方庫。

然後像之前在專案settings.py中註冊我們自己編寫的APP一樣,註冊bootstrap3這個應用程式。

還需要包含django-bootstrap3包含jQuery,在settings.py末尾新增如下程式碼:

-- snip --
LOGIN_URL = '/users/login/'

# django-bootstrap3的設定
BOOTSTRAP3 = {
    "include_jquery": True,
}
複製程式碼

2.1 修改base.html

2.1.1 定義HTML頭部

實現訪問專案的每個頁面時,瀏覽器標題都現實這個網站的名稱。另外還新增了一些在模板中使用Bootstrap所需的資訊。刪除base.html的全部程式碼,並新增如下程式碼:

{% load bootstrap3 %}

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="x-ua-compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
    
  <title>Learning Log</title>

  {% bootstrap_css %}
  {% bootstrap_javascript %}
</head>
</html>
複製程式碼

第12行使用了django-bootstrap3的一個自定義模板標籤,它讓Django包含所有的Bootstrap樣式檔案。第13行啟用可能在頁面中使用的所有互動式行為,如可摺疊的導航欄。

2.1.2 定義導航欄

-- snip --
</head>
<body>
<!-- Static navbar -->
<nav class="navbar navbar-default navbar-static-top">
  <div class="container">

    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" 
              data-target="#navbar" aria-expanded="false" aria-controls="navbar">
      </button>
      <a class="navbar-brand" href="{% url 'learning_logs:index' %}">Learning Log</a>
    </div>

    <div id="navbar" class="navbar-collapse collapse">
      <ul class="nav navbar-nav">
        <li><a href="{% url 'learning_logs:topics' %}">Topics</a></li>
      </ul>

      <ul class="nav navbar-nav navbar-right">
        {% if user.is_authenticated %}
          <li><a>Hello, {{ user.username }}.</a></li>
          <li><a href="{% url 'users:logout' %}">log out</a></li>
        {% else %}
          <li><a href="{% url 'users:register' %}">register</a></li>
          <li><a href="{% url 'users:login' %}">log in</a></li>
        {% endif %}
      </ul>
    </div><!--/.nav-collapse -->

  </div>
</nav>
</body>
</html>
複製程式碼

navbarnavbar-defaultnavbar-static-top是三個選擇器,在nav塊中的內容將根據選擇器在Bootstrap中定義的樣式規則來設定樣式(額,html中選擇器的概念有點忘了,不過不要緊,我們的任務並不是研究HTML)。在第20-28行中是我們之前編寫的判斷語句,只不過被放在了ul塊中,並且設定了一個選擇器navbar-right

2.1.3 定義頁面的主要部分

-- snip --
</head>
<body>
-- snip --
<div class="container">

  <div class="page-header">
    {% block header %}{% endblock %}
  </div>
  <div>
    {% block content %}{% endblock %}
  </div>

</div> <!-- /container -->
</body>
</html>
複製程式碼

這部分包含一個div塊,該塊的class屬性是container(容器),容器中包含兩個元素:一個新增的header塊和之前用到的content塊。header塊的內容告訴使用者頁面包含哪些資訊以及使用者可以在頁面上執行哪些操作,其class屬性值page-header將一系列樣式應用於這個塊。base.html的修改到此為止。

2.2 使用jumbotron設定主頁樣式

下面使用新定義的header塊及另一個名為jumbotron的Bootstrap元素修改主頁。jumbotron元素是一個大框,通常用於在主頁中呈現專案的簡要描述,修改index.html

{% extends "learning_logs/base.html" %}

{% block header %}
  <div class="jumbotron">
    <h1>Track your learning.</h1>
  </div>
{% endblock header %}

{% block content %}
  <h2>
    <a href="{% url 'users:register' %}">Register an account</a>to make your own
    Learning Log, and list the topics you're learning about.
  </h2>
  <h2>
    Whenever you learn something new about a topic, make an entry summarizing
    what you've learned.
  </h2>
{% endblock content %}
複製程式碼

header塊中,我們用一個jumbotron元素來修飾一條簡短的標語,讓首次訪問者大致知道網站功能。隨後再content塊中描述了兩種主要操作。下圖是實際效果:

Python學習之路19-設定應用程式的樣式並對其進行部署

2.3 設定登入頁面樣式

現在的程式碼改進了登入頁面的整體外觀(因為修改了base.html),現在來改進登入表單,修改login.html

{% extends "learning_logs/base.html" %}
{% load bootstrap3 %}

{% block header %}
  <h2>Log in to your account.</h2>
{% endblock header %}

{% block content %}

  <form class="form" method="post" action="{% url 'users:login' %}">
    {% csrf_token %}
    {% bootstrap_form form %}

    {% buttons %}
      <button class="btn btn-primary" name="submit">log in</button>
    {% endbuttons %}
    <input type="hidden" name="next" value="{% url 'learning_logs:index' %}"/>
  </form>

{% endblock content %}
複製程式碼

第2行程式碼載入了bootstrap3模板標籤;

header塊描述這個頁面時做什麼的;

刪除了之前的if form.errors程式碼塊,因為django-bootstrap3位自動管理表單錯誤;

form塊中新增了屬性“form",然後使用標籤模板bootstrap_form來顯示錶單,這個標籤替換掉了之前的form.as_p

button也使用Bootstrap樣式進行了替換,下面是實際效果圖:

Python學習之路19-設定應用程式的樣式並對其進行部署

2.4 設定new_topic.html頁面樣式

{% extends "learning_logs/base.html" %}
{% load bootstrap3 %}

{% block header %}
  <h2>Add a new topic:</h2>
{% endblock header %}

{% block content %}

  <form class="form" action="{% url 'learning_logs:new_topic' %}" method="post">
    {% csrf_token %}
    {% bootstrap_form %}

    {% buttons %}
      <button class="btn btn-primary" name="submit">add topic</button>
    {% endbuttons %}
  </form>

{% endblock content %}
複製程式碼

上面的修改大多都類似於對login.html的修改。

2.5 設定topics.html頁面樣式

{% extends "learning_logs/base.html" %}

{% block header %}
  <h1>Topics</h1>
{% endblock header %}

{% block content %}

  <ul>
    {% for topic in topics %}
      <li>
        <h3>
          <a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a>
        </h3>
      </li>
    {% empty %}
      <li>No topics have been added yet.</li>
    {% endfor %}
  </ul>
  <h3><a href="{% url 'learning_logs:new_topic' %}">Add a new topic:</a></h3>
  
{% endblock content %}
複製程式碼

這裡並沒有載入bootstrap3,因為該檔案中並沒有使用任何bootstrap3自定義標籤。

2.6 設定topic.html中條目的樣式

topic頁面包含的內容比其他大部分頁面都多,所以樣式設定要多一些,我們將使用Bootstrap皮膚(panel)來突出每個條目。

{% extends "learning_logs/base.html" %}

{% block header %}
  <h2>{{ topic }}</h2>
{% endblock header %}

{% block content %}
  <p>
    <a href="{% url 'learning_logs:new_entry' topic.id %}">add new entry</a>
  </p>

  {% for entry in entries %}
    <div class="panel panel-default">
      <div class="panel-heading">
        <h3>
          {{ entry.date_added|date:"M d, Y H:i" }}
          <small>
            <a href="{% url 'learning_logs:edit_entry' entry.id %}">edit
              entry</a>
          </small>
        </h3>
      </div>
      <div class="panel-body">
        {{ entry.text|linebreaks }}
      </div>
    </div> <!-- panel -->
  {% empty %}
    <li>
      There are no entries for this topic yet.
    </li>
  {% endfor %}

{% endblock content %}
複製程式碼

只修改了樣式,並沒有修改Django程式碼。下圖是實際效果:

Python學習之路19-設定應用程式的樣式並對其進行部署

至此已完成了對頁面的修改。

3. 部署“學習筆記”

由於對Web應用不是很瞭解,筆者查閱資料現在大多用Apache和Nginx來部署Web專案,但本書使用Heroku來部署我們的Web專案。

請到Heroku的官網註冊賬號,它提供免費使用服務,併到https://toolbelt.heroku.com/ 下載命令列工具。

同時,還需要在Django專案所在的虛擬環境中安裝一些額外的包:

dj-database-url:幫助Django與Heroku使用的資料庫進行通訊;

dj-staticstatic3:幫助Django正確管理靜態檔案(靜態檔案包括樣式規則和JavaScript檔案);

gunicorn:一個伺服器軟體,能夠在線上環境中支援應用程式提供的服務。

3.1 建立包含包列表的檔案requirements.txt

Heroku需要知道我們的專案依賴於哪些包,使用pip命令來生成這個檔案:

(venv)learning_log>pip freeze > requirements.txt
複製程式碼

下面是這個檔案所包含的內容(“如果是Windows系統,看到的內容可能不全”——這是書中提示,然而這裡的內容還比書中多了一個pytz):

dj-database-url==0.5.0
dj-static==0.0.6
Django==2.0.4
django-bootstrap3==9.1.0
gunicorn==19.7.1
pytz==2018.4
static3==0.7.0
複製程式碼

在部署專案時,Heroku將建立一個環境,並根據這個檔案安裝其中的所有包。也因此,專案部署到Heroku後,行為將與它在本地系統上一樣。

還需要在包列表中新增psycopg2,它幫助Heroku管理活動資料庫。需在requirements.txt最後一行新增如下程式碼:psycopg2>=2.6.1。該語句表示,有新版則裝最新版,沒有的話最低安裝2.6.1版本。

3.2 確定Python版本

如果沒有指定Python版本,Heroku將使用其當前的Python預設版本。下面來確保Heroku使用我們所使用的版本。如果不知道使用的python的版本,請在專案所在虛擬環境中執行python --version

(venv)learning_log>python --version
Python 3.6.4
複製程式碼

再在manage.py所在的資料夾中新建一個名為runtime.txt的檔案,輸入Python的版本:

python-3.6.4
複製程式碼

注意:單詞小寫,中間有一個連字元!

3.3 為部署到Heroku而修改settings.py

settings.py末尾新增一個片段,指定一些Heroku環境設定:

-- snip --
# 書中的判斷語句是 if os.getcwd() == '/app': 
# 現在估計是Heroku升級了,改為了下面的語句,否則待會兒部署的時候會出錯
if os.environ['HOME'] == "/app":
    import dj_database_url

    DATABASES = {
        "default": dj_database_url.config(default="postgres://localhost")
    }

    # 讓request.is_secure()承認X-Forwarded-Proto頭
    SECURE_PROXY_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

    # 支援所有的主機頭(host header)
    ALLOWED_HOSTS = ["*"]

    # 靜態資產配置
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    # 書中設定是這樣的: STATIC_ROOT = "staticfiles"
    STATIC_ROOT = os.path.join(BASE_DIR, 'static')
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR, "static"),
    )
複製程式碼

第2行中,使用getcwd()函式獲取當前的工作目錄,在Heroku中,這個目錄總/app。在本地部署中,這個目錄通常是專案檔案的名稱。這個if測試確保僅當專案被部署到Heroku時才執行這個程式碼塊。這種結構讓我們能夠將統一配置檔案用於本地開發環境和線上伺服器。

在第3行,匯入了dj_database_url,用於在Heroku上配置伺服器。Heroku使用PostgreSQL(也叫Postgres,一種比SQLite更高階的資料庫),這些配置使得專案在Heroku上使用該資料庫。

其他配置作用分別如下:支援HTTPS請求(第10行);讓Django能夠使用Heroku的URL來提供專案支援的服務(第13行);設定專案,使其能夠在Heroku上正確地提供靜態檔案(第16-20行)。

3.4 建立啟動程式的Procfile

Procfile告訴Heroku啟動那些程式,以便能夠正確地提供專案支援的服務。這個檔案只包含一行,檔名為Procfile,不帶副檔名,儲存到專案根目錄。

web: gunicorn learning_log.wsgi --log-file -
複製程式碼

這段程式碼讓Heroku將gunicorn用過伺服器,並使用learning_log/wsgi.py中的設定來啟動應用程式。標誌log-file告訴Heroku應將哪些型別的時間寫入日誌。

3.5 為部署到Heroku而修改wsgi.py

因為Heroku需要的設定與目前一直使用的設定稍有不同,所以還需要修改wsgi.py檔案:

import os

from django.core.wsgi import get_wsgi_application
from dj_static import Cling

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "learning_log.settings")

# 原始碼是 application = get_wsgi_application()
application = Cling(get_wsgi_application())
複製程式碼

注意,這裡只有第4,9行是新增的,其餘都是自帶的。

3.6 建立用於儲存靜態檔案的目錄

在Heroku上,Django蒐集所有的靜態檔案,並將它們放在一個地方,以便高效管理。我們需要手動建立這樣一個資料夾。在專案資料夾learning_log中,也有一個名為learning_log的子資料夾,在這個子資料夾中,新建一個名為static的資料夾,即這個資料夾的路徑為:learning_log/learning_log/static/。由於專案被推送到Heroku時,它將不包含空資料夾,所以,在static資料夾中還需要建立一個佔位檔案placeholder.txt

This file ensures that learning_log/static/ will be added to the project.
Django will collect static files and place them in learning_log/static/.
複製程式碼

3.7 在本地使用gunicorn伺服器

如果你使用的是Linux或OS X,可在部署到Heroku前嘗試在本地使用gunicorn伺服器。為此,在虛擬環境中執行命令:

(ll_env)learning_log$ heroku local
Installing Heroku Toolbelt v4... done
-- snip --
forego | starting web.1 on port 5000
web.1 | [2018-04-27 14:00:00 -0800] [12875] [INFO] Starting gunicorn 19.3.0
-- snip --
複製程式碼

但如果使用的是Windows,請跳過這個步驟(筆者用的是Windows,所以上面的輸出是從書上照搬過來的)。

3.8 使用Git跟蹤專案檔案

Heroku Toolbelt包含Git,這裡不再介紹Git怎麼安裝。

Git跟蹤誰修改了專案,即便專案由一個人開發。為了實現跟蹤,需要提供使用者名稱和email,但對於聯絡專案,這倆都可以隨便起:

(ll_env)learning_log$ git config --global user.name "example"
(ll_env)learning_log$ git config --global user.email "test@example.com"
複製程式碼

我們無需讓Git跟蹤專案中的每個檔案,因此將讓Git忽略一些檔案。在專案根目錄下建立一個名為 .gitignore 的檔案,注意前面有一個實心句點,不含副檔名。在檔案中輸入:

ll_env/
__pycache__/
*.sqlite3
複製程式碼

忽略ll_env目錄是因為隨時都可以重新建立它;忽略__pycache__是因為這個目錄包含了Django執行.py檔案時自動建立的.pyc檔案,目前都是本地資料(如果使用的是python2.7,請將__pycache__替換為*.pyc);沒有跟蹤本地資料庫是因為如果你在伺服器上使用的是SQLite,當你將專案推送到伺服器時,可能會不小心把伺服器上的資料給覆蓋掉。

最後,我們提交專案,而在提交之前需要為我們的專案初始化一個Git倉庫,將所有必要的檔案都加入到這個倉庫中,並提交專案的初始狀態,如下:

(ll_env) learning_log>git init
Initialized empty Git repository in E:/Code/Python/learning_log/.git/

(ll_env) learning_log>git add .

(ll_env) learning_log>git commit -am "Ready for deployment to heroku."
[master (root-commit) 4109cbc] Ready for deployment to heroku.
 39 files changed, 745 insertions(+)
 create mode 100644 .gitignore
 -- snip --
 create mode 100644 users/views.py

(ll_env) learning_log>git status
On branch master
nothing to commit, working tree clean
複製程式碼

第一個命令在“學習筆記”所在的目錄中初始化一個空倉庫;第二個命令(最後有個句點!)將未被忽略的檔案都新增到這個倉庫中;第三個命令中的標誌 -a 讓Git在這個提交中包含所有修改過的檔案,而標誌 -m 讓Git記錄一條日誌訊息;第四個命令的輸出表明當前位於分支master中,而工作目錄是乾淨(clean)的,每當要將專案推送到Heroku時,都希望看到這個狀態。

3.9 推送到Heroku

現在開始推送專案。在專案的虛擬環境中執行下面的命令:

(ll_env) learning_log>heroku login
Enter your Heroku credentials:
Email: kevinwen701@gmail.com
Password: ************
Logged in as kevinwen701@gmail.com

(ll_env) learning_log>heroku create
Creating app... done, ⬢ pure-anchorage-27981
https://pure-anchorage-27981.herokuapp.com/ | https://git.heroku.com/pure-anchorage-27981.git

(ll_env) learning_log>git push heroku master
Counting objects: 46, done.
-- snip --
remote: Verifying deploy... done.
To https://git.heroku.com/pure-anchorage-27981.git
 * [new branch]      master -> master
複製程式碼

首先,在終端會話中,使用你在Heroku官網建立的賬號登陸,然後讓Heroku建立一個空專案。Heroku生成的專案名由兩個單詞和一個數字組成(可以修改)。然後我們讓Git將專案分值master推送到Heroku剛才建立的倉庫中;Heroku隨後使用這些檔案在其伺服器上建立專案。最後輸出資訊還給出了訪問這個專案的URL。

大概上述命令執行完後,專案便部署好了,但還未對其做全面的配置。為核實正確地啟動了伺服器程式,請執行命令heroku ps

(ll_env) learning_log>heroku ps
Free dyno hours quota remaining this month: 550h 0m (100%)
For more information on dyno sleeping and how to upgrade, see:
https://devcenter.heroku.com/articles/dyno-sleeping

=== web (Free): gunicorn learning_log.wsgi --log-file - (1)
web.1: up 2018/04/27 16:36:42 +0800 (~ 6m ago)
複製程式碼

當執行了這條命令後,輸出指出專案還可在多長時間內處於活動狀態。當超過這個時間後,將顯示標準的伺服器錯誤頁面,而稍後我們將設定這個錯誤頁面。在倒數第二行,我們發現啟動了Procfile指定的程式。

現在,我們可以使用命令heroku open在瀏覽器中開啟這個APP了:

(ll_env) learning_log>heroku open
複製程式碼

它將自動開啟瀏覽器,顯示專案的主頁。

3.10 在Heroku上建立資料庫

要對Heroku專案執行Django和Python命令,可使用命令heroku run

(ll_env) learning_log>heroku run python manage.py migrate
Running python manage.py migrate on ⬢ pure-anchorage-27981... up, run.9204 (Free)
-- snip --
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
  -- snip --
  Applying learning_logs.0003_topic_owner... OK
  Applying sessions.0001_initial... OK
複製程式碼

當執行上述命令後,Heroku建立一個終端會話來執行命令migrate(第2行)。從第6行起,Django應用預設遷移以及我們在開發“學習筆記”期間生成的遷移。

現在可以像在本地系統上一樣使用它。然而其中並沒有任何資料,因為之前的測試資料並沒有複製到伺服器中,而且也不建議將測試資料複製到伺服器中。

3.11 改進Heroku部署

3.11.1 在Heroku上建立超級使用者

從上面的命令可以看出,我們可以使用heroku run來執行一次性命令,但可以這樣執行命令:在連線到了Heroku伺服器的情況下,使用命令heroku run bash來開啟Bash終端會話。我們將使用Bash終端會話來建立超級使用者,以便能夠訪問線上應用程式的管理網站:

(ll_env) learning_log>heroku run bash
Running bash on ⬢ pure-anchorage-27981... up, run.8093 (Free)
~ $ ls
learning_log  learning_logs  manage.py  Procfile  requirements.txt  runtime.txt  users
~ $ python manage.py createsuperuser
/app/.heroku/python/lib/python3.6/site-packages/psycopg2/__init__.py:144: UserWarning:
The psycopg2 wheel package will be renamed from release 2.8; in order to keep installing
from binary please use "pip install psycopg2-binary" instead. For details see: 
<http://initd.org/psycopg/docs/install.html#binary-install-from-pypi>.
  """)
Username (leave blank to use 'u10229'): ll_admin
Email address:
Password:
Password (again):
Superuser created successfully.
~ $ exit
exit
(venv) learning_log>
複製程式碼

進入Bash後,我們首先執行了ls命令,以檢視伺服器上有哪些檔案和目錄,發現和本地系統相同。然後我們執行了常見超級使用者的命令,執行過程和之前建立超級使用者一樣。現在可以通過在APP的URL後面加/admin/來登陸管理網站了。

3.11.2 在Heroku上建立對使用者友好的URL

由於在伺服器上我們的專案名不是learning_log,而是其他自動生成的名字,為此,我們使用一個命令來重新命名這個APP:

(ll_env) learning_log>heroku apps:rename kevins-learning-log
Renaming pure-anchorage-27981 to kevins-learning-log... done
https://kevins-learning-log.herokuapp.com/ | https://git.heroku.com/kevins-learning-log.git
Git remote heroku updated
 !    Don't forget to update git remotes for all other local checkouts of the app.
複製程式碼

3.12 確保專案的安全

當前這個專案存在一個嚴重的安全問題:settings.py中包含設定DEBUG=True,它在發生錯誤時顯示除錯資訊。開發專案時,Django的錯誤頁面向你顯示了重要的除錯資訊,如果將專案部署到伺服器後依然保留這個設定,講給攻擊者提供大量可供利用的資訊。我們還需要確保任何人都無法看到這些資訊,也不能冒充專案託管網站來重定向請求。

下面修改settings.py檔案,以讓我們能夠在本地看到錯誤資訊,但部署到伺服器後不顯示任何錯誤資訊:

-- snip --
if os.environ["HOME"] == "/app":
    -- snip --
    # 只允許Heroku託管這個專案
    ALLOWED_HOSTS = ["kevins-learning-log.herokuapp.com"]
    
    DEBUG = False
    -- snip --
複製程式碼

然後我們提交併推送修改。先將修改提交到Git倉庫,在推送到Heroku:

(venv) E:\Code\Python\learning_log>git commit -am "Set DEBUG=False for heroku."
[master 563b175] Set DEBUG=False for heroku.
 1 file changed, 6 insertions(+), 4 deletions(-)

(venv) E:\Code\Python\learning_log>git status
On branch master
nothing to commit, working tree clean

(venv) E:\Code\Python\learning_log>git push heroku master
-- snip --
remote: -----> Python app detected
remote: -----> Installing requirements with pip
-- snip --
remote: -----> Launching...
remote:        Released v7
remote:        https://kevins-learning-log.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/kevins-learning-log.git
   9bc1c2d..563b175  master -> master

複製程式碼

Heroku發現倉庫發生了變化,因此重建了專案,確保所有的修改都已生效。它不會重建資料庫,因此本次無需執行命令migrate

現在如果訪問未定義的擴充套件將會看到一個標準的錯誤頁面,它不包含任何關於專案的具體資訊。

3.13 建立自定義錯誤頁面

編寫兩個風格與我們專案相符的404和500錯誤頁面模板。這些模板必須放在根模板目錄中。為此,在資料夾leraning_log/learning_log中新建一個資料夾templates,再在這個資料夾中新建一個404.html檔案,並輸入如下內容:

{% extends "learning_logs/base.html" %}

{% block header %}
  <h2>The item you requested is not available.(404)</h2>
{% endblock header %}
複製程式碼

再建立一個名為500.html的檔案:

{% extends "learning_logs/base.html" %}

{% block header %}
  <h2>There has been an internal error. (500)</h2>
{% endblock header %}
複製程式碼

這些新檔案要求對settings.py做細微的修改:

-- snip --
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'learning_log/templates')],
        'APP_DIRS': True,
        -- snip --
    },
]
-- snip --
複製程式碼

在將修改推送到伺服器之前,可以在本地檢視錯誤頁面時什麼樣的,不過得先在本地設定DEBUG=False

# settings.py檔案
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False

ALLOWED_HOSTS = ["localhost"]
複製程式碼

現在本地訪問不存在的頁面時將得到我們自定義的錯誤頁面。

最後,想之前一樣,將修改推送到伺服器,程式碼不再演示,注意為推送新增一條簡短的日誌資訊。

現在,如果使用者手工請求不存在的主題或條目將導致500錯誤。Django嘗試渲染請求的頁面,但沒有足夠的資訊來完成這項任務,進而引發500錯誤。對於這種情況,將其視為404錯誤更合適,為此可使用Django快捷函式get_object_or_404()。這個函式嘗試從資料庫獲取請求的物件,當物件不存在時,引發404錯誤。我們在views.py中匯入這個函式,並用它替換函式get()

from django.shortcuts import render, get_object_or_404
@login_required
def topic(request, topic_id):
    """顯示單個主題及其所有的條目"""
    topic = get_object_or_404(Topic, id=topic_id)
    -- snip --
複製程式碼

再次提交併推送修改。

3.14 部署總結

從前面這些例子可看出,開發與部署的過程如下:

①修改專案。如果建立了新檔案,使用命令 git add. (最後有個句點!)將它們加到Git倉庫中。如果要遷移資料庫,也需要執行該命令,因為每個遷移都生成了新的遷移檔案。

②執行 git commit -am "commit message",將修改提交到倉庫。

③執行 git push heroku master 將修改推送到伺服器。

④如果本地遷移了資料庫,也需要遷移線上資料庫,可以使用一次性命令 heroku run python manage.py migrate ,也可以使用 heroku run bash開啟一個遠端終端會話,再執行遷移。

3.15 設定SECRET_KEY

Django根據settings.py中的SECRET_KEY來實現大量的安全協議。本專案中設定的SECRET_KEY對一個練習專案來說已經足夠了,但是對於生產網站,請務必認真對待這個值。

3.16 將專案從Heroku刪除

Heroku限制了你可免費託管的專案數,另外,我們也不希望自己的賬戶中塞滿大量的聯絡專案。除了可以登入到Heroku,在應用程式的Settings中手動刪除專案,也可以在命令列中執行如下命令刪除專案:

(ll_env)learning_log$ heroku apps:destroy --app appname
複製程式碼

4. 總結

現在大家可以訪問這個網站kevins-learning-log.herokuapp.com(筆者在免費期過期前不會刪除這個網站)。本篇主要介紹瞭如何使用Bootstrap來設定網頁的樣式,並學習瞭如何將專案部署到Heroku的伺服器上。至此,Python的Django入門已經完成,這本書也已經看完。暫時告一段落。


迎大家關注我的微信公眾號"程式碼港" & 個人網站 www.vpointer.net ~

Python學習之路19-設定應用程式的樣式並對其進行部署

相關文章