1. 程式人生 > >完整的Django入門指南學習筆記2

完整的Django入門指南學習筆記2

part2:

前沿

在第一節中,我們安裝了專案所需要的一切:Python3.6以及在虛擬環境中執行的Django2.0,這部分教程繼續在專案上編寫程式碼。

開始寫程式碼前,先討論下專案的相關背景知識,然後再學習 Django 的基礎,包括:模型、管理後臺、檢視、模板和路由。


論壇專案

在進入模型,檢視等其它有趣的部分之前,花點時間簡要地討論我們將要開發的這個專案。

例圖

我們的專案是一個論壇系統,整個專案的構思是維護幾個論壇版塊(boards),每個版塊就像一個分類一樣。在指定的版塊裡面,使用者可以通過建立新主題(Topic)開始討論,其他使用者參與討論回覆。

我們需要找到一種方法來區分普通使用者和管理員使用者,因為只有管理員可以建立版塊。下圖概述了主要的用例和每種型別的使用者角色:

類圖

從用例圖中,我們可以開始思考專案所需的實體類有哪些。這些實體就是我們要建立的模型,它與我們的Django應用程式處理的資料非常密切。

為了能夠實現上面描述的用例,我們需要至少實現下面幾個模型:Board,Topic,Post和User。

  • Board:版塊
  • Topic:主題
  • Post:帖子(譯註:其實就是主題的回覆或評論)

類與類之間的實線告訴我們,在一個主題(Topic)中,我們需要有一個欄位(譯註:其實就是通過外來鍵來關聯)來確定它屬於哪個版塊(Board)。

同樣,帖子(Post)也需要一個欄位來表示它屬於哪個主題,這樣我們就可以列出在特定主題內建立的帖子。

最後,我們需要一個欄位來表示主題是誰發起的,帖子是誰發的。

使用者和版塊之間也有聯絡,就是誰建立的版塊。但是這些資訊與應用程式無關。還有其他方法可以跟蹤這些資訊,稍後你會看到。

現在我們的類圖有基本的表現形式,我們還要考慮這些模型將承載哪些資訊。這很容易讓事情變得複雜,所以試著先把重要的內容列出來,這些內容是我們啟動專案需要的資訊。後面我們再使用 Django 的遷移(Migrations)功能來改進模型,你將在下一節中詳細瞭解這些內容。

但就目前而言,這是模型最基本的內容:

這個類圖強調的是模型之間的關係,這些線條和箭頭最終會在稍後轉換為欄位。

對於 Board 模型,我們將從兩個欄位開始:name

 和 description。 name欄位必須是唯一的,為了避免有重複的名稱。description 用於說明這個版塊是做什麼用的。

Topic 模型包括四個欄位:subject 表示主題內容,last_update 用來定義話題的排序,starter 用來識別誰發起的話題,board 用於指定它屬於哪個版塊。

Post 模型有一個 message 欄位,用於儲存回覆的內容,created_at 在排序時候用(最先發表的帖子排最前面),updated_at 告訴使用者是否更新了內容,同時,還需要有對應的 User 模型的引用,Post 由誰建立的和誰更新的。

最後是 User 模型。在類圖中,我只提到了欄位 usernamepasswordemail, is_superuser 標誌,因為這幾乎是我們現在要使用的所有東西。

需要注意的是,我們不需要建立 User 模型,因為Django已經在contrib包中內建了User模型,我們將直接拿來用。

關於類圖之間的對應關係(數字 1,0..* 等等),這裡教你如何閱讀:

一個topic 必須與一個(1)Board(這意味著它不能為空)相關聯,但是 Board 下面可能與許多個或者0個 topic 關聯 (0..*)。這意味著 Board 下面可能沒有主題。(譯註:一對多關係)

一個 Topic 至少有一個 Post(發起話題時,同時會發佈一個帖子),並且它也可能有許多 Post(1..*)。一個Post 必須與一個並且只有一個Topic(1)相關聯。

一個 Topic 必須有一個且只有一個 User 相關聯,topic 的發起者是(1)。而一個使用者可能有很多或者沒有 topic(0..*)。

Post 必須有一個並且只有一個與之關聯的使用者,使用者可以有許多或沒有 Post(0..*)。Post 和 User之間的第二個關聯是直接關聯(參見該行最後的箭頭),就是 Post 可以被使用者修改(updated_by),updated_by 有可能是空(Post 沒有被修改)

畫這個類圖的另一種方法是強調欄位而不是模型之間的關係:

上面的表示方式與前面的表示方式是對等的,不過這種方式更接近我們將要使用 Django Models API 設計的內容。在這種表示方式中,我們可以更清楚地看到,在 Post 模型中,關聯了 Topic,created_by(建立者)和 updated_by(更新者)欄位。

另一個值得注意的事情是,在 Topic 模型中,有一個名為 posts()的操作(一個類方法)。我們將通過反向關係來實現這一目標,Django 將自動在資料庫中執行查詢以返回特定主題的所有帖子列表。

好了,現在已經夠UML了!為了繪製本節介紹的圖表,我使用了 StarUML 工具。

線框圖(原型圖)

花了一些時間來設計應用程式的模型後,我們來建立一些線框來定義需要完成的工作,並且清楚地瞭解我們將要做什麼。

基於線框圖,我們可以更深入地瞭解應用程式中涉及的實體。

首先,我們需要在主頁上顯示所有版塊:

如果使用者點選一個連結,比如點選Django版塊,它應該列出所有Django相關的主題:

這裡有兩個入口:使用者點選“new topic“ 按鈕建立新主題,或者點選主題連結檢視或參與討論。

“new topic” 頁面:

現在,主題頁面顯示了帖子和討論:

如果使用者點選回覆按鈕,將看到下面這個頁面,並以倒序的方式(最新的在第一個)顯示帖子列表:

繪製這些線框,你可以使用draw.io服務,它是免費的

這一部分我們設計的系統的模型,以及模型之間的關係,分清楚了不同使用者型別的角色,最後,我們把原型圖也畫出來了。再小的系統,我們也要先思考。下面我們將設計 Model 類。


模型

我們在本節中要做的是建立 Django 所表示的類,這些類就是在上一部分中設計的類:Board,Topic 和 Post。User 模型被命名為內建應用叫 auth,它以名稱空間 django.contrib.auth的形式出現在 INSTALLED_APPS 配置中。

修改 boards/models.py 。以下是我們在Django應用程式中如何表示類圖的程式碼:

from django.db import models
from django.contrib.auth.models import User class Board(models.Model): name = models.CharField(max_length=30, unique=True) description = models.CharField(max_length=100) class Topic(models.Model): subject = models.CharField(max_length=255) last_updated = models.DateTimeField(auto_now_add=True) board = models.ForeignKey(Board, related_name='topics') starter = models.ForeignKey(User, related_name='topics') class Post(models.Model): message = models.TextField(max_length=4000) topic = models.ForeignKey(Topic, related_name='posts') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(null=True) created_by = models.ForeignKey(User, related_name='posts') updated_by = models.ForeignKey(User, null=True, related_name='+') 

所有模型都是django.db.models.Model類的子類。每個類將被轉換為資料庫表。每個欄位由 django.db.models.Field子類(內建在Django core)的例項表示,它們並將被轉換為資料庫的列。

欄位 CharFieldDateTimeField等等,都是 django.db.models.Field 的子類,包含在Django的核心裡面,隨時可以使用。

在這裡,我們僅使用 CharFieldTextFieldDateTimeField,和ForeignKey 欄位來定義我們的模型,當然在Django提供了更廣泛的選擇來代表不同型別的資料。

有些欄位需要引數,例如CharField。我們應該始終設定一個 max_length。這些資訊將用於建立資料庫列。Django需要知道資料庫列需要多大。該 max_length引數也將被Django Forms API用來驗證使用者輸入。

在Board模型定義中,更具體地說,在name欄位中,我們設定了引數 unique=True,顧名思義,它將強制資料庫級別欄位的唯一性。

在Post模型中,created_at欄位有一個可選引數auto_now_add=True:告訴Django建立Post物件時間為當前日期和時間。

模型之間的關係使用ForeignKey欄位。它將在模型之間建立一個連線,並在資料庫級別建立適當的關係(譯註:外來鍵關聯)。該ForeignKey欄位需要一個位置引數related_name:用於引用它關聯的模型。(譯註:例如 created_by 是外來鍵欄位,關聯的User模型,表明這個帖子是誰建立的,related_name=posts 表示在 User 那邊可以使用 user.posts 來檢視這個使用者建立了哪些帖子)

例如,在Topic模型中,board欄位是Board模型的ForeignKey。它告訴Django,一個Topic例項只涉及一個Board例項。related_name引數將用於建立反向關係,Board例項通過屬性topics訪問屬於這個版塊下的Topic列表。

Django自動建立這種反向關係,related_name是可選項。但是,如果我們不為它設定一個名稱,Django會自動生成它:(class_name)_set。例如,在Board模型中,所有Topic列表將用topic_set屬性表示。而這裡我們將其重新命名為了topics,以使其感覺更自然。

在Post模型中,該updated_by欄位設定related_name='+'。這指示Django我們不需要這種反向關係,所以它會被忽略(譯註:也就是說我們不需要關係使用者修改過哪些帖子)。

下面可以看到類圖和Django模型的原始碼之間的比較,綠線表示我們如何處理反向關係。

這時,你可能會問自己:“主鍵/ ID呢?”?如果我們沒有為模型指定主鍵,Django會自動為我們生成它。所以現在一切正常。在下一節中,您將看到它是如何工作的。


遷移模型

下一步是告訴Django建立資料庫,以便我們可以開始使用它。

開啟終端 ,啟用虛擬環境,轉到 manage.py 檔案所在的資料夾,然後執行以下命令:

python manage.py makemigrations

你會看到輸出的內容是:

Migrations for 'boards':
  boards/migrations/0001_initial.py
    - Create model Board
    - Create model Post
    - Create model Topic
    - Add field topic to post
    - Add field updated_by to post

此時,Django 在 boards/migrations 目錄建立了一個名為 0001_initial.py 的檔案。它代表了應用程式模型的當前狀態。在下一步,Django將使用該檔案建立表和列。

遷移檔案將被翻譯成SQL語句。如果您熟悉SQL,則可以執行以下命令來檢驗將是要被資料庫執行的SQL指令

python manage.py sqlmigrate boards 0001

如果你不熟悉SQL,也不要擔心。在本系列教程中,我們不會直接使用SQL。所有的工作都將使用Django ORM來完成,它是一個與資料庫進行通訊的抽象層。

下一步是將我們生成的遷移檔案應用到資料庫:

python manage.py migrate

輸出內容應該是這樣的:

Operations to perform:
  Apply all migrations: admin, auth, boards, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying boards.0001_initial... OK
  Applying sessions.0001_initial... OK

因為這是我們第一次遷移資料庫,所以 migrate 命令把 Django contrib app 中現有的遷移檔案也執行了,這些內建app列在了 INSTALLED_APPS 。這是預料之中的。

Applying boards.0001_initial... OK 是我們在上一步中生成的遷移指令碼。

好了!我們的資料庫已經可以使用了。

  • 需要注意的是SQLite是一個產品級資料庫。SQLite被許多公司用於成千上萬的產品,如所有Android和iOS裝置,主流的Web瀏覽器,Windows 10,MacOS等。
  • 但這不適合所有情況。SQLite不能與MySQL,PostgreSQL或Oracle等資料庫進行比較。大容量的網站,密集型寫入的應用程式,大的資料集,高併發性的應用使用SQLite最終都會導致問題。
  • 我們將在開發專案期間使用SQLite,因為它很方便,不需要安裝其他任何東西。當我們將專案部署到生產環境時,再將切換到PostgreSQL(譯註:後續,我們後面可能使用MySQL)。對於簡單的網站這種做法沒什麼問題。但對於複雜的網站,建議在開發和生產中使用相同的資料庫。

試驗 Models API

使用Python進行開發的一個重要優點是互動式shell。我一直在使用它。這是一種快速嘗試和試驗API的方法。

您可以使用 manage.py 工具載入我們的專案來啟動 Python shell :

python manage.py shell
Python 3.6.2 (default, Jul 17 2017, 16:44:45) [GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)] on darwin Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> 

這與直接輸入python指令來呼叫互動式控制檯是非常相似的,除此之外,專案將被新增到sys.path並載入Django。這意味著我們可以在專案中匯入我們的模型和其他資源並使用它。

讓我們從匯入Board類開始:

from boards.models import Board

要建立新的 board 物件,我們可以執行以下操作:

board = Board(name='Django', description='This is a board about Django.') 

為了將這個物件儲存在資料庫中,我們必須呼叫save方法:

board.save()

save()方法用於建立和更新物件。這裡Django建立了一個新物件,因為這時Board 例項沒有id。第一次儲存後,Django會自動設定ID:

board.id
1

您可以將其餘的欄位當做Python屬性訪問:

board.name
'Django'
board.description
'This is a board about Django.'

要更新一個值,我們可以這樣做:

board.description = 'Django discussion board.'
board.save() 

每個Django模型都帶有一個特殊的屬性; 我們稱之為模型管理器(Model Manager)。你可以通過屬性objects 來訪問這個管理器,它主要用於資料庫操作。例如,我們可以使用它來直接建立一個新的Board物件:

board = Board.objects.create(name='Python', description='General discussion about Python.') 
board.id
2
board.name
'Python'

所以,現在我們有兩個版塊了。我們可以使用objects列出資料庫中所有現有的版塊:

Board.objects.all() <QuerySet [<Board: Board object>, <Board: Board object>]> 

結果是一個QuerySet。稍後我們會進一步瞭解。基本上,它是從資料庫中查詢的物件列表。我們看到有兩個物件,但顯示的名稱是 Board object。這是因為我們尚未實現 Board 的__str__ 方法。

__str__方法是物件的字串表示形式。我們可以使用版塊的名稱來表示它。

首先,退出互動式控制檯:

exit()

現在編輯 boards app 中的 models.py 檔案:

class Board(models.Model): name = models.CharField(max_length=30, unique=True) description = models.CharField(max_length=100) def __str__(self): return self.name 

讓我們重新查詢,再次開啟互動式控制檯:

 python manage.py shell
from boards.models import Board

Board.objects.all() <QuerySet [<Board: Django>, <Board: Python>]> 

好多了,對吧?

我們可以將這個QuerySet看作一個列表。假設我們想遍歷它並列印每個版塊的描述:

boards_list = Board.objects.all() for board in boards_list: print(board.description) 

結果是:

Django discussion board.
General discussion about Python. 

同樣,我們可以使用模型的 管理器(Manager) 來查詢資料庫並返回單個物件。為此,我們要使用get()方法:

django_board = Board.objects.get(id=1) django_board.name 'Django' 

但我們必須小心這種操作。如果我們試圖查詢一個不存在的物件,例如,查詢id=3的版塊,它會引發一個異常:

board = Board.objects.get(id=3) boards.models.DoesNotExist: Board matching query does not exist. 

get()方法的引數可以是模型的任何欄位,但最好使用可唯一標識物件的欄位來查詢。否則,查詢可能會返回多個物件,這也會導致異常。

Board.objects.get(name='Django') <Board: Django> 

請注意,查詢區分大小寫,小寫“django”不匹配:

Board.objects.get(name='django') boards.models.DoesNotExist: Board matching query does not exist. 

模型操作的總結

下面是我們在本節中關於模型學到的方法和操作,使用Board模型作為參考。大寫的 Board 指的是類,小寫的 board 指 Board 的一個例項(或物件)

操作 程式碼示例
建立一個物件而不儲存 board = Board()
儲存一個物件(建立或更新) board.save()
資料庫中建立並儲存一個物件 Board.objects.create(name='...', description='...')
列出所有物件 Board.objects.all()
通過欄位標識獲取單個物件 Board.objects.get(id=1)

在下一小節中,我們將開始編寫檢視並在HTML頁面中顯示我們的版塊。


檢視、模板和靜態檔案

目前我們已經有一個檢視函式叫home,這個檢視在我們的應用程式主頁上顯示為 “Hello,World!”

myproject/urls.py

from django.conf.urls import url
from django.contrib import admin from boards import views urlpatterns = [ url(r'^$', views.home, name='home'), url(r'^admin/', admin.site.urls), ] 

boards/views.py

from django.http import HttpResponse

def home(request): return HttpResponse('Hello, World!') 

我們可以從這裡開始寫。如果你回想起我們的原型圖,圖5顯示了主頁應該是什麼樣子。我們想要做的是在表格中列出一些版塊的名單以及它們的描述資訊。

首先要做的是匯入Board模型並列出所有的版塊

boards/views.py

from django.http import HttpResponse
from .models import Board def home(request): boards = Board.objects.all() boards_names = list() for board in boards: boards_names.append(board.name) response_html = '<br>'.join(boards_names) return HttpResponse(response_html) 

結果就是這個簡單的HTML頁面:

等等,我們在這裡先停一下。真正的專案裡面我們不會這樣去渲染HTML。對於這個簡單檢視函式,我們做的就是列出所有版塊,然後渲染部分是Django模板引擎的職責。


模板引擎設定

在 manage.py 所在的目錄建立一個名為 templates 的新資料夾:

myproject/
 |-- myproject/
 |    |-- boards/
 |    |-- myproject/
 |    |-- templates/  
 |    +-- manage.py
 +-- venv/

在templates資料夾中,建立一個名為home.html的HTML檔案:

templates/home.html

<!DOCTYPE html>
<html>
  <head> <meta charset="utf-8"> <title>Boards</title> </head> <body> <h1>Boards</h1> {% for board in boards %} {{ board.name }} <br> {% endfor %} </body> </html> 

在上面的例子中,我們混入了原始HTML和一些特殊標籤 {% for ... in ... %} 和 {{ variable }} 。它們是Django模板語言的一部分。上面的例子展示瞭如何使用 for遍歷列表物件。{{ board.name }}會在 HTML 模板中會被渲染成版塊的名稱,最後生成動態HTML文件。

在我們可以使用這個HTML頁面之前,我們必須告訴Django在哪裡可以找到我們應用程式的模板。

開啟myproject目錄下面的settings.py檔案,搜尋TEMPLATES變數,並設定DIRS 的值為 os.path.join(BASE_DIR, 'templates')

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(BASE_DIR, 'templates')
        ],
        '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',
            ],
        },
    },
]

本質上,剛新增的這一行所做的事情就是找到專案的完整路徑並在後面附加“/templates”

我們可以使用Python shell進行除錯:

python manage.py shell
from django.conf import settings

settings.BASE_DIR '/Users/vitorfs/Development/myproject' import os os.path.join(settings.BASE_DIR, 'templates') '/Users/vitorfs/Development/myproject/templates' 

看到了嗎?它只是指向我們在前面步驟中建立的templates資料夾。

現在我們可以更新home檢視:

boards/views.py

from django.shortcuts import render
from .models import Board def home(request): boards = Board.objects.all() return render(request, 'home.html', {'boards': boards}) 

生成的HTML:

我們可以用一個更漂亮的表格來替換,改進HTML模板:

templates/home.html

<!DOCTYPE html>
<html>
  <head> <meta charset="utf-8"> <title>Boards</title> </head> <body> <h1>Boards</h1> <table border="1"> <thead> <tr> <th>Board</th> <th>Posts</th> <th>Topics</th> <th>Last Post</th> </tr> </thead> <tbody> {% for board in boards %} <tr> <td> {{ board.name }}<br> <small style="color: #888">{{ board.description }}</small> </td> <td>0</td> <td>0</td> <td></td> </tr> {% endfor %} </tbody> </table> </body> </html> 


第一個測試用例

測試主頁

測試將是一個反覆出現的主題,我們將在整個教程系列中一起探討不同的概念和策略。

我們來開始寫第一個測試。現在,我們將在boards應用程式內的tests.py檔案中操作

boards/tests.py

from django.core.urlresolvers import reverse
from django.test import TestCase class HomeTests(TestCase): def test_home_view_status_code(self): url = reverse('home') response = self.client.get(url) self.assertEquals(response.status_code, 200) 

這是一個非常簡單但非常有用的測試用例,我們測試的是請求該URL後返回的響應狀態碼。狀態碼200意味著成功。

請求一下主頁後,我們可以在控制檯中看到響應的狀態程式碼:

如果出現未捕獲的異常,語法錯誤或其他任何情況,Django會返回狀態程式碼500,這意味著是內部伺服器錯誤。現在,想象我們的應用程式有100個檢視函式。如果我們為所有檢視編寫這個簡單的測試,只需一個命令,我們就能夠測試所有檢視是否返回成功程式碼,因此使用者在任何地方都看不到任何錯誤訊息。如果沒有自動化測試,我們需要逐一檢查每個頁面是否有錯誤。

執行Django的測試套件:

python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced). . ---------------------------------------------------------------------- Ran 1 test in 0.041s OK Destroying test database for alias 'default'... 

現在我們可以測試Django是否在請求的URL的時候返回了正確的檢視函式。這也是一個有用的測試,因為隨著開發的進展,您會發現urls.py 模組可能變得非常龐大而複雜。URL conf 全部是關於解析正則表示式的。有些情況下有一個非常寬容的URL(譯註:本來不應該匹配的,卻因為正則表示式寫的過於寬泛而錯誤的匹配了),所以Django最終可能返回錯誤的檢視函式。

我們可以這樣做:

boards/tests.py

from django.core.urlresolvers import reverse
from django.urls import resolve from django.test import TestCase from .views import home class HomeTests(TestCase): def test_home_view_status_code(self): url = reverse('home') response = self.client.get(url) self.assertEquals(response.status_code, 200) def test_home_url_resolves_home_view(self): view = resolve('/') self.assertEquals(view.func, home) 

在第二個測試中,我們使用了resolve函式。Django使用它來將瀏覽器發起請求的URL與urls.py模組中列出的URL進行匹配。該測試用於確定URL / 返回 home 檢視。

再次測試:

python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 2 tests in 0.027s

OK
Destroying test database for alias 'default'...

要檢視有關測試執行時更詳細的資訊,可將verbosity的級別設定得更高一點:

python manage.py test --verbosity=2
Creating test database for alias 'default' ('file:memorydb_default?mode=memory&cache=shared')...
Operations to perform:
  Synchronize unmigrated apps: messages, staticfiles
  Apply all migrations: admin, auth, boards, contenttypes, sessions
Synchronizing apps without migrations:
  Creating tables...
    Running deferred SQL...
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying boards.0001_initial... OK
  Applying sessions.0001_initial... OK
System check identified no issues (0 silenced).
test_home_url_resolves_home_view (boards.tests.HomeTests) ... ok
test_home_view_status_code (boards.tests.HomeTests) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.017s

OK
Destroying test database for alias 'default' ('file:memorydb_default?mode=memory&cache=shared')...

Verbosity決定了將要列印到控制檯的通知和除錯資訊量; 0是無輸出,1是正常輸出,2是詳細輸出。


靜態檔案設定

靜態檔案是指 CSS,JavaScript,字型,圖片或者是用來組成使用者介面的任何其他資源。

實際上,Django 本身是不負責處理這些檔案的,但是為了讓我們的開發過程更輕鬆,Django 提供了一些功能來幫助我們管理靜態檔案。這些功能可在 INSTALLED_APPS 的 django.contrib.staticfiles 應用程式中找到(譯者:Django為了使得開發方便,也可以處理靜態檔案,而在生產環境下,靜態檔案一般直接由 Nginx 等反向代理伺服器處理,而應用伺服器專心負責處理它擅長的業務邏輯)。

市面上很多優秀前端元件框架,我們沒有理由繼續用簡陋的HTML文件來渲染。我們可以輕鬆地將Bootstrap 4新增到我們的專案中。Bootstrap是一個用HTML,CSS和JavaScript開發的前端開源工具包。

在專案根目錄中,除了 boards, templates 和myproject資料夾外,再建立一個名為static的新資料夾,並在static資料夾內建立另一個名為css的資料夾:

myproject/
 |-- myproject/
 |    |-- boards/
 |    |-- myproject/
 |    |-- templates/
 |    |-- static/       <-- here
 |    |    +-- css/     <-- and here
 |    +-- manage.py
 +-- venv/

轉到getbootstrap.com並下載最新版本:

下載編譯版本的CSS和JS

在你的計算機中,解壓 bootstrap-4.0.0-beta-dist.zip 檔案,將檔案 css/bootstrap.min.css複製到我們專案的css資料夾中:

myproject/
 |-- myproject/
 |    |-- boards/
 |    |-- myproject/
 |    |-- templates/
 |    |-- static/
 |    |    +-- css/
 |    |         +-- bootstrap.min.css    <-- here
 |    +-- manage.py
 +-- venv/

下一步是告訴Django在哪裡可以找到靜態檔案。開啟settings.py,拉到檔案的底部,在STATIC_URL後面新增以下內容:

STATIC_URL = '/static/'

STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ] 

還記得 TEMPLATES 目錄嗎,和這個配置是一樣的

現在我們必須在模板中載入靜態檔案(Bootstrap CSS檔案):

templates/home.html

{% load static %}<!DOCTYPE html>
<html>
  <head> <meta charset="utf-8"> <title>Boards</title> <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}"> </head> <body> <h1>Boards</h1> <table border="1"> <thead> <tr> <th>Board</th> <th>Posts</th> <th>Topics</th> <th>Last Post</th> </tr> </thead> <tbody> {% for board in boards %} <tr> <td> {{ board.name }}<br> <small style="color: #888">{{ board.description }}</small> </td> <td>0</td> <td>0</td> <td></td> </tr> {% endfor %} </tbody> </table> </body> </html> 

首先,我們在模板的開頭使用了 Static Files App 模板標籤 {% load static %}

模板標籤{% static %}用於構成資原始檔完整URL。在這種情況下,{% static 'css/bootstrap.min.css' %}將返回 /static/css/bootstrap.min.css,它相當於 http://127.0.0.1:8000/static/css/bootstrap.min.css

{% static %}模板標籤使用 settings.py檔案中的 STATIC_URL 配置來組成最終的URL,例如,如果您將靜態檔案託管在像 https://static.example.com/ 這樣的子域中 ,那麼我們將設定 STATIC_URL=https://static.example.com/ ,然後 {% static 'css/bootstrap.min.css' %}返回的是 https://static.example.com/css/bootstrap.min.css

如果目前這些對你來說搞不懂也不要擔心。只要記得但凡是需要引用CSS,JavaScript或圖片檔案的地方就使用{% static %}。稍後,當我們開始部署專案到正式環境時,我們將討論更多。現在都設定好了。

重新整理頁面 http://127.0.0.1:8000 ,我們可以看到它可以正常執行:

現在我們可以編輯模板,以利用Bootstrap CSS:

{% load static %}<!DOCTYPE html>

            
           

相關推薦

完整Django入門指南學習筆記2

part2: 前沿 在第一節中,我們安裝了專案所需要的一切:Python3.6以及在虛擬環境中執行的Django2.0,這部分教程繼續在專案上編寫程式碼。 開始寫程式碼前,先討論下專案的相關背景知識,然後再學習 Django 的基礎,包括:模型、管理後臺、檢視、模板和路由。 論壇專案 在進入模型

完整Django入門指南學習筆記1

轉自【https://blog.csdn.net/qq_35554125/article/details/79462885】 part 1: 前沿 教程材料一共會被分為七個部分。 此教程將從安裝、開發環境的準備,模型,檢視,模板,URL到更高階的主題(如遷移,測試和部署)中詳細探討所有基本概念。 安裝

完整Django入門指南學習筆記4

前言 這一章節將會全面介紹 Django 的身份認證系統,我們將實現註冊、登入、登出、密碼重置和密碼修改的整套流程。 同時你還會了解到如何保護某些試圖以防未授權的使用者訪問,以及如何訪問已登入使用者的個人資訊。 在接下來的部分,你會看到一些和身份驗證有關線框圖,將在本教程中實現。之後是一個全新Djang

完整Django入門指南學習筆記3

前言 在本節課中,我們將深入理解兩個基本概念: URLs 和 Forms。在這個過程中,我們還將學習其它很多概念,如建立可重用模板和安裝第三方庫。同時我們還將編寫大量單元測試。 如果你是從這個系列教程的 part 1 跟著這個教程一步步地編寫專案,你可能需要在開始之前更新&n

完整Django入門指南學習筆記7 網頁自動翻譯

轉自【https://simpleisbetterthancomplex.com/series/2017/10/16/a-complete-beginners-guide-to-django-part-7.html】 Django的初學者指南 - 第7部分  2017年10月16日&nbs

【第一部分-django論壇從搭建到部署】一個完整Django入門指南學習筆記

前沿 教程材料一共會被分為七個部分。 此教程將從安裝、開發環境的準備,模型,檢視,模板,URL到更高階的主題(如遷移,測試和部署)中詳細探討所有基本概念。 安裝 公眾號裡邊的是Mac下的教程,我的系統是win,這也是為啥我做這個筆

python入門教程學習筆記#2

tab 下載 body 中文 穩定 出現 包含 圖1 ret 2.1 python3.6 工具使用 運行python 自帶的idle後,輸入python命令,如print(‘hello world‘),回車後輸出 hello world 其中mac系統會出現一段warn

Scikit-Learn 與 TensorFlow 機器學習實用指南學習筆記2 — 機器學習的主要挑戰

紅色石頭的個人網站:redstonewill.com 簡而言之,因為機器學習的主要任務就是選擇合適的機器學習演算法在資料集上進行訓練,所以不好的演算法和不好的資料都可能嚴重影響訓練效果。下面我們先來看看不好的資料會帶來什麼影響。 1.4.1 訓練資料不足

kubernetes 權威指南學習筆記(2) -- 基本概念和術語

基本概念和術語 Master&Node Kubernetes 叢集的兩種管理角色: Master 和 Node Maste

Netty權威指南2學習筆記2——NIO入門

傳統的BIO程式設計 網路程式設計的基本模型是Client/Server模型,通過三次揚建立連線,如果連線建立成功,雙方就可以通過網路套接字進行通訊。 BIO通訊模型圖 採用BIO通訊模型的服務端,通常由一個獨立的Acceptor執行緒負責監聽客戶

OpenCV3.4.3最新版本安裝詳解!VS2013平臺下,解決X86沒有問題。《OpenCV3程式設計入門》第1章基本知識--學習筆記2

第一步開啟opencv官方網站,下載opencv最新穩定版本: https://opencv.org/releases.html 點選以後,會跳轉網頁,進入網頁後,會等待下載,大概5秒鐘就會提示你下載。    (我的網頁下載比較慢,所以複製了下載連結,在迅雷

《SQL 學習指南》(第 3 版)學習筆記(2) - 第 2 章 建立和使用資料庫

2.1 建立 MySQL 資料庫 (如果要匯入示例 .sql 指令碼檔案,除了書上的 8 個步驟,我另外做幾點修正和補充: a. P 14 面倒數第 4 行給的連結失效了,正確的連結:https://resources.oreilly.com/examples/9780596007

誰說菜鳥不會資料分析(入門篇)----- 學習筆記2(結構為王:確定分析思路 4P 5W2H )

1、資料分析方法論 確定分析思路需要以營銷、管理等理論為指導,把這些跟資料分析相關的營銷、管理等理論統稱為資料分析方法論。 資料分析方法論主要用來指導資料分析師進行一次完整的資料分析,更多的是指資料分析思路,如從哪方面開展資料分析?各方面包含什麼內容和指標。 資料分析方法論主要

Arduino 入門學習筆記2 三色LED實驗

電路 程式: /*************************************************** name:RGB LED ****************************************************/ int redPi

Python爬蟲(入門+進階)學習筆記 2-6 Scrapy的Request和Response詳解

上節課我們學習了中介軟體,知道了怎麼通過中介軟體執行反反爬策略。本節課主要介紹Scrapy框架的request物件和response物件 通常,Request物件在爬蟲程式中生成並傳遞到系統,直到它們到達下載程式,後者執行請求並返回一個Response物件,

SpringMVC學習指南筆記2

基於模型-檢視-控制器模式(MVC) 檢視負責應用的展示; 模型封裝了應用的資料和業務邏輯;控制器負責接收使用者輸入、改變模型、調整檢視的顯示。 控制器:springmvc和struct1使用servlet作為控制器,struct2使用filter作為控制器。 檢視:大部分使用JSP頁面作為檢視。

少兒程式設計Scratch學習筆記2--官方初學指南

下載完軟體,可以看一下官方的初學指南。學習下基本的操作。 Scratch主要由角色和背景兩部分構成。其中角色和背景都是由指令碼,造型和聲音組成的。 開啟軟體就可以看見下面的介面了。 在紅色的指令碼區域,是可以拖拽動作到黃色的區域去完成相關角色的動作。 點選黃色

Hadoop學習筆記2.不怕故障的海量儲存:HDFS基礎入門

一.HDFS出現的背景   隨著社會的進步,需要處理資料量越來越多,在一個作業系統管轄的範圍存不下了,那麼就分配到更多的作業系統管理的磁碟中,但是卻不方便管理和維護—>因此,迫切需要一種系統來管理多臺機器上的檔案,於是就產生了分散式檔案管理系統,英文名成為DFS(Distributed File Sy

Python爬蟲(入門+進階)學習筆記 2-1 爬蟲工程化及Scrapy框架初窺

本章節將會系統地介紹如何通過Scrapy框架把爬蟲工程化。本節主要內容是:簡單介紹Python和爬蟲的關係,以及將要使用的Scrapy框架的工作流程。Python適合做爬蟲的原因語言本身簡單,適合敏捷開發有比較完善的工具鏈足夠靈活,以應對各種突然狀況爬蟲的知識體系前端相關知識:html,css,js;瀏覽器相

一個完整Django入門指南

這一部分的教程介紹的是模型、檢視、模板、測試和管理 介紹 歡迎來到我們的Django教程的第二部分!在上一部分中,我們安裝了所有我們需要的東西。希望您已經安裝了Python 3.6,並在虛擬環境中執行Django 1.11。我們已經建立了一個我們