首頁>科技>

Django 是 Python 社群的兩大最受歡迎的 Web 框架之一(另一個是 Flask)。憑藉功能強大的腳手架和諸多開箱即用的元件,用 Django 搭建 Web 應用快速而又省力。然而,也正是因為過於強大,想要駕馭它需要花費不少的力氣。本文將通過實現一個新聞釋出網站帶你快速熟悉 Django 框架,讓你能夠騎上這匹快馬,在 Web 開發的戰場上盡情馳騁。

高度強調可複用性和可插拔性,內建大量現成的成熟元件,開發效率極高自帶與資料庫聯動的後臺管理系統,能夠在開發的同時建立內容

Django 的名字取自吉他手 Django Reinhardt,發音為 JANG-goh(諧音“尖狗”),但實際上 Django 的吉祥物是一隻長著翅膀的小馬。

在這篇教程中,我們也將向 Django 的起源致敬——手把手帶你開發一個新聞釋出網站,並且可以從後臺管理系統中新增新聞,展示到網站首頁上。

預備知識

本教程假定你已經知道了:

基本的 Python 3 語言知識,包括使用 pip 安裝包了解 HTTP 協議基礎知識,瀏覽器和伺服器之間是如何互動的學習目標

讀完這篇教程後,你將掌握 Django MTV 框架的精髓:

M(Model):建立資料模型,並執行資料庫遷移T(Template):寫出基本的 Django 模板,並從檢視中傳入資料V(View):在檢視中訪問資料庫,實現業務邏輯,渲染模板,並接入路由表

雖然 Django 還有很多知識點,但是理解了 MTV,後面的知識點學習起來也就輕鬆多啦。

安裝 Django 並啟用腳手架

本文假定你已經安裝好了 Python 3 和 pip,那麼可以直接用 pip 安裝 Django:

pip install django

直接用 pip 在全域性安裝 Django 的確不是一個很好的做法,用虛擬環境更符合最佳實踐。為了減少初學者們的認知負擔,在這裡就簡化了安裝過程。熟悉 pipenv 等虛擬環境工具的老司機當然可以自行使用哈。

安裝好 Django 後,我們用 Django 自帶的腳手架工具 django-admin 建立專案:

django-admin startproject django_newscd django_news

生成的專案骨架及每個檔案的作用如下所示:

django_news├── django_news // 專案全域性檔案目錄│ ├── __init__.py│ ├── settings.py // 全域性配置│ ├── urls.py // 全域性路由│ └── wsgi.py // WSGI服務介面(暫時不用糾結這個是神馬)└── manage.py // 專案管理指令碼

我們使用 manage.py 來執行開發伺服器(Development Server):

python manage.py runserver

提示

細心的你會發現出現了一行鮮紅色的提示:You have 17 unapplied migration(s)...(省略 n 個字元)。不用擔心,我們會在接下來的步驟中詳細講解來龍去脈。

提示

Django 開發伺服器可以保持開啟,並且後面修改程式碼會自動重新載入,非常方便。後面執行其他命令時,再開啟一個終端(命令列)即可。

一切準備就緒,韁繩已在你手中!

建立第一個自定義 Django App

在上一節中我們講到,Django 是一個高度模組化的框架。具體而言,一個 Django 應用由多個子應用組成,我們一般稱之為 App(注意不是我們常說的移動應用 APP,而是 Application 的簡寫),如下圖所示。

內建:即 Django 框架自帶的應用,包括 admin(後臺管理)、auth(身份鑑權)、sessions(會話管理)等等自定義:即用來實現我們自身業務邏輯的應用,這裡我們將建立一個新聞展示應用第三方:即社群提供的應用,數量極其豐富,功能涵蓋幾乎所有方面,能夠大大減少開發成本

所有的 Django 應用都在 django_news/settings.py 的 INSTALLED_APPS 列表中定義:

INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles',]實現自定義 App

話不多說,讓我們來建立第一個自定義 App,名稱為 news:

python manage.py startapp news

生成的 news 應用資料夾結構如下所示:

news // news 應用目錄├── __init__.py // 初始化模組├── admin.py // 後臺管理配置├── apps.py // 應用配置├── migrations // 資料庫遷移檔案目錄│ └── __init__.py // 資料庫遷移初始化模組├── models.py // 資料模型├── tests.py // 單元測試└── views.py // 檢視

這個子目錄裡面乍一看好多檔案啊!這是因為 Django 始終堅持解耦的原則——儘量減少程式碼之間的耦合,把不相關的程式碼拆成多個模組,讓同一個模組具有內聚性。相信我,等到後面慢慢熟悉之後,你會對每一個模組都了如指掌的。

實際上,每個 Django App 的組織結構符合 Django 的 MTV 法則——Model(模型)+ Template(模板)+ View(檢視)。MTV 與大家比較熟悉的 MVC 在思想上非常相似,但是命名有比較大的出入,如下表所示:

大家熟知的 View,在 Django 裡面代表的是業務邏輯,也就是 MVC 中的控制器哦!

將自定義 App 新增到全域性配置

最後,我們在 settings.py 中將 news 應用加入 INSTALLED_APPS 中:

# ...INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'news',]

至此,我們已經建立了第一個 Django 應用!但是現在這個應用還沒有任何內容,我們接下來將逐步完善這個應用。

在檢視(View)中寫一點業務邏輯接入路由,使其能夠被訪問Django 的路由系統

Django 的路由系統是由全域性路由和子應用路由組成。簡單來說,根據使用者輸入的 URL,全域性路由表進行匹配並選擇正確的子應用路由,再由所選擇的子應用路由匹配並選擇正確的檢視(View)。整個流程如下圖所示:

例如,使用者訪問 example.com/apple/buy,然後全域性路由根據 /apple/buy 先選擇 apple 的路由表,再從 apple 路由表中根據 /buy 選擇 /buy 路由,然後執行 /buy 對應的 BuyView 檢視,返回給使用者結果。

編寫第一個檢視

對檢視訪問的流程大致了解之後,我們就可以開始動手了。首先開啟 news/views.py,寫一個簡單的檢視函式,返回一串 Hello World!:

from django.http import HttpResponsedef index(request): return HttpResponse('Hello World!')

上面這個 index 函式可以說是一個最簡單的檢視函數了,實際大部分應用的檢視要比這複雜得多。Django 同時支援基於函式的檢視(FBV,Function-based View)和基於類的檢視(CBV,Class-based View),這裡顯然是 FBV,接收一個 request 請求物件作為引數,返回了一個 HttpResponse 物件。

將檢視接入路由

接著,我們要讓路由系統能夠訪問到剛才寫好的檢視函式。因此先實現子應用 news 的路由表,建立 news/urls.py 檔案如下:

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

每一個 Django 路由表模組(urls.py)中都約定必須包含一個 urlpatterns 列表用來存放路由對映表。列表中每個元素是一個用 django.urls.path 函式封裝好的路由對映,通常接收以下三個引數:

route:必須,即實際的訪問路由,空字串等於 /,即空路由view:必須,該路由將要訪問的檢視name:可選,該路由的名稱,方便後續在模板中使用

我們將剛剛寫好的 news 路由表接入全域性路由表。由於我們希望新聞能夠展示在首頁(即通過 / 就能訪問,無需 /news),因此 news 應用路由在全域性路由中的 URL 是一個空字串。在 django_news/urls.py 中修改如下:

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

這裡使用 django.urls.include 函式將 news 應用的路由表接入進來,並且 include 函式的引數是路由模組路徑的字串 news.urls,省去了手動 import 的麻煩。

注意

新增路由規則時順序是很重要的,因為在嘗試匹配時會按照從上到下的順序進行,因此應該把最模糊的路由(即空路由)放在最下面。

如果你開發伺服器還在執行(如果沒有可以再開啟),訪問 localhost:8000,就可以看到那一串熟悉的字元了:

理解模板:網頁前端的實現

上一步中,我們學會了如何實現檢視,並將其接入路由配置中,使其能夠被使用者訪問。接下來,我們將實現一個 Django 模板作為網頁前端,從而給使用者呈現更豐富的內容。

提示

如果你有過其他模板(或者類似技術)的開發經驗,例如 Jinja、EJS 或是 JSP 等,對 Django 模板會有一種似曾相識的感覺。如果你不了解什麼是模板引擎,也不用擔心,簡單的理解就是一個可以填充內容、甚至能夠加入程式碼邏輯的類似 HTML 文件,最終會被轉換成瀏覽器能夠識別的 HTML 文件。

Django 模板語言基礎

Django 模板本質上是一個 HTML 文件,只不過通過一些特殊的語法實現資料的填充。這裡我們講解一下最常用的三個語法:

表示式插值

最常用的語法,沒有之一。通過在一對花括號 {{}} 放入一個表示式,就能夠在檢視中傳入表示式中變數的內容,並最終渲染成包含變數具體內容的 HTML 程式碼。需要注意的是,所支援的表示式僅支援以下形式(可以自由組合):

<h1>{{ name }}</h1><p>{{ news.title }}</p><p>{{ news.visitors.0 }}</p>

如果我們在檢視中傳入以下上下文字典(Context Dictionary):

{ 'name': 'Tuture', 'news': { 'title': 'Hello World', 'visitors': ['Tom', 'Marc'], }}

那麼最終渲染成的 HTML 程式碼就是:

<h1>Tuture</h1><p>Hello World</p><p>Tom</p>

條件語句

條件語句的定義如下:

{% if is_true %} <h1>It is true!</h1>{% else %} <h1>It is false!</h1>{% endif %}

如果變數 is_true 為真,那麼最終渲染出來的就是 <h1>It is true!</h1>,否則就是 <h1>It is false!</h1>。注意:整個條件語句必須以 {% endif %} 結束,並且 {% else %} 是可選的。

迴圈語句

迴圈語句用來在模板上展示任意長的列表內容。其語法如下:

{% for elem in some_list %} <p>{{ elem }}</p>{% endfor %}

如果傳入的 some_list 為 ['Apple', 'Banana', 'Orange'],那麼渲染出的 HTML 程式碼就是:

<p>Apple</p><p>Banana</p><p>Orange</p>實現第一個 Django 模板

到了動手時間了,我們先實現第一個 Django 模板。在 news 目錄中建立一個 templates 目錄,再在 templates 目錄中建立一個 news 目錄,並在內層的 news 目錄中建立 index.html 檔案:

mkdir -p news/templates/newstouch news/templates/news/index.html

思考

聽上去很麻煩,只建立 news/templates,然後把模板放裡面不就好了,為什麼還要再建立一個 news 目錄?這是由於 Django 的模板查詢機制會將所有應用裡面的模板全部收集到一起,如果兩個模板的名字衝突,就會導致其中一個模板不能被正確訪問。如果放在 news 子資料夾裡面,就能夠通過 news/index.html 訪問,通過名稱空間的機制避免了衝突。

模板的程式碼如下:

{% if news_list %} <ul> {% for elem in news_list %} <li> <h3>{{ elem.title }}</h3> <p>{{ elem.content }}</p> </li> {% endfor %} </ul>{% else %} <p>暫無新聞</p>{% endif %}

這短短几行模板程式碼卻很好地覆蓋了我們剛剛講述的三個模板語法:表示式插值、條件語句和迴圈語句。如果忘記其中某個地方是什麼意思的話,翻上去看看吧!

完成模板的編寫後,我們要在檢視中對其進行渲染。開啟 news/views.py 檔案,修改程式碼如下:

from django.shortcuts import renderdef index(request): context = { 'news_list': [ { "title": "圖雀寫作工具推出了新的版本", "content": "隨隨便便就能寫出一篇好教程,真的很神奇", }, { "title": "圖雀社群正式推出快速入門系列教程", "content": "一杯茶的功夫,讓你快速上手,絕無擔憂", }, ] } return render(request, 'news/index.html', context=context)

這裡我們呼叫 django.shortcuts.render 函式來渲染模板,這個函式通常接受三個引數(有其他引數,但是這裡我們不關心):

request:請求物件,直接把檢視的引數 request 傳進來就可以template_name:模板名稱,這裡就是我們剛剛建立的 news/index.htmlcontext:傳入模板的上下文物件,必須是一個字典,字典中的每個鍵對應模板中的變數。這裡我們弄了些假資料,假裝是從資料庫裡面取來的。

再訪問 localhost:8000,看一下我們的首頁是不是有內容了:

完美!

理解模型:和資料庫的聯動

Django 的 MTV,我們已經講了 T(Template)和 V(View),現在來到了最後一關: M(Model)了。資料模型是 Django 入門最大的難點,消化這一步的內容需要花點力氣,但是相信我,當你邁過 M 這最後一關,你便能真正上手 Django 開發了!下面我們先介紹一下 Django 的資料模型設計。

Django 在資料模型方面的設計堪稱典範,列舉一些閃光點:

由於高度解耦的設計,可輕鬆切換各種關係型資料庫(預設的 SQLite,可選 MySQL、PostgreSQL、Oracle 等等)強大的 ORM(Object Relation Mapping,物件關係對映)模組,使得用 Python 操作資料庫非常輕鬆,免去了使用 SQL 的麻煩優秀的資料庫遷移機制(Migration),修改資料模式(Schema)比較方便,能夠適應不斷變化的功能需求

對於初學者而言,我們暫且選擇預設的 SQLite 資料庫,省去了配置資料庫的煩惱。在後面的進階教程中,我們會切換到其他適合生產環境的資料庫。

理解 ORM

簡單來說,ORM 能夠將面向物件的程式碼轉換成相應的 SQL 語句,從而對資料庫進行操作。SQL 是用於訪問和處理資料庫的標準的計算機語言,但是直接寫在程式碼裡面顯然難以維護,而且對使用者的要求也非常高,寫的糟糕的 SQL 程式碼查詢效率非常低下。因此,使用設計良好的 ORM 不僅讓程式碼可讀性更好,也能幫助開發者進行查詢優化,節省不少力氣。

我們來看一些簡單的 Django ORM 例子:

# 查詢所有模型# 等價於 SELECT * FROM BlogBlog.objects.all()# 查詢單個模型# 等價於 SELECT * FROM Blog WHERE ID=1Blog.objects.get(id=1)# 新增單個模型# 等價於 INSERT INTO Blog (title, content) VALUES ('hello', 'world')blog = Blog(title='hello', content='world')blog.save()

有木有感覺操作起來比 SQL 方便很多呢?

理解資料庫遷移

資料庫遷移是指將用 Django 定義的模型轉換成 SQL 程式碼(即遷移檔案),並在資料庫中進行建表操作(或更新表)。看下面這張圖就知道了:

一般的開發流程就是這樣:

用 Django 定義了一個新的資料模型用 makemigrations 命令建立遷移檔案(儲存在子應用的 migrations 目錄裡面)用 migrate 命令執行遷移在開發中發現第 1 步中定義的模型不完善,更新資料模型跳轉到第 2 步,反覆迴圈實現第一個資料模型

終於到了動手的環節。我們首先定義資料模型 Post ,包括標題 title 欄位和 content 欄位,程式碼如下:

from django.db import modelsclass Post(models.Model): title = models.CharField(max_length=200) content = models.TextField() def __str__(self): return self.title

定義好之後,執行以下命令建立遷移檔案:

python manage.py makemigrations

可以看到輸出如下:

Migrations for 'news': news/migrations/0001_initial.py - Create model Post

並且成功地自動建立了 news/migrations/0001_initial.py 遷移指令碼。接著我們進行資料庫遷移:

python manage.py migrate

輸出如下圖所示:

資料庫遷移完成後,我們就可以建立用於登入後臺管理的超級使用者:

python manage.py createsuperuser

按照提示填寫使用者名稱和密碼即可。然後訪問 localhost:8000/admin,進入後臺系統的登入頁面:

填入剛才設定的使用者名稱和密碼,進入後臺管理頁面:

咦,我們剛才建立的 news 應用還有 Post 模型去哪了?

配置後臺管理介面

那是因為我們沒有實現 news 應用的後臺管理介面。在 news/admin.py 中填入程式碼如下:

from django.contrib import adminfrom .models import Postadmin.site.register(Post)

再次進入後臺管理系統,可以看到我們的 news 應用和 Post 模型了:

大概添加個兩三條新聞就差不多啦。你也可以進一步探索後臺管理系統,包括修改新聞、新增使用者等等,都可以。

在檢視中新增資料查詢

最後,我們在檢視中加入從資料庫中查詢的程式碼:

from django.shortcuts import renderfrom .models import Postdef index(request): context = { 'news_list': Post.objects.all() } return render(request, 'news/index.html', context=context)

訪問網站首頁,可以看到剛才在後臺管理系統新增的新聞了:

希望這篇教程能夠讓你對 Django 最重要的一些概念和操作有了基本的了解。Django 還有很多很多的高階玩法,例如資料模型中的高階查詢、欄位索引、更換資料庫等等,模板中的繼承機制、內部標籤等等,還有檢視中如何處理各類請求(POST、PUT等),我們會在後續更多教程中逐一為大家講解,不見不散!

最新評論
  • 整治雙十一購物亂象,國家再次出手!該跟這些套路說再見了
  • 運營商突然宣佈!iPhone使用者猝不及防,果粉:對華為太偏心