一杯茶的時間,上手 Django 框架開發

Django 是 Python 社區的兩大最受歡迎的 Web 框架之一(另外一個是 Flask)。憑藉功能強大的腳手架和諸多開箱即用的組件,用 Django 搭建 Web 應用快速而又省力。然而,也正是由於過於強大,想要駕馭它須要花費很多的力氣。本文將經過實現一個新聞發佈網站帶你快速熟悉 Django 框架,讓你可以騎上這匹快馬,在 Web 開發的戰場上盡情馳騁。html

提示前端

這篇文章寫做時用的是 Django 2.x 版本,發表時已經推出了 3.x 版本。不過通過筆者測試,這篇文章中的代碼對於 2.x 和 3.x 都適用哦!python

起步

Django 由 Adrian Holovaty 和 Simon Willison 在 2003 年的秋天寫成,並在 2005 年正式發佈。他們倆當時爲一個新聞報社製做網站,對快速開發有着比較高的需求,而且但願可以在開發的同時也可以讓非技術人員爲網站添加內容。因而這也使得 Django 具有了兩項鮮明的特色:數據庫

  • 高度強調可複用性可插拔性,內置大量現成的成熟組件,開發效率極高
  • 自帶與數據庫聯動的後臺管理系統,可以在開發的同時建立內容

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

在這篇教程中,咱們也將向 Django 的起源致敬——手把手帶你開發一個新聞發佈網站,而且能夠從後臺管理系統中添加新聞,展現到網站首頁上。瀏覽器

預備知識

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

  • 基本的 Python 3 語言知識,包括使用 pip 安裝包
  • 瞭解 HTTP 協議基礎知識,瀏覽器和服務器之間是如何互動的

學習目標

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

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

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

安裝 Django 並啓用腳手架

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

pip install django
複製代碼

直接用 pip 在全局安裝 Django 的確不是一個很好的作法,用虛擬環境更符合最佳實踐。爲了減小初學者們的認知負擔,在這裏就簡化了安裝過程。熟悉 pipenv 等虛擬環境工具的老司機固然能夠自行使用哈。

安裝好 Django 後,咱們用 Django 自帶的腳手架工具 django-admin 建立項目:

django-admin startproject django_news
cd 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 個字符)。不用擔憂,咱們會在接下來的步驟中詳細講解前因後果。

按照提示,咱們經過瀏覽器訪問 localhost:8000,能夠看到歡迎界面:

提示

Django 開發服務器能夠保持開啓,而且後面修改代碼會自動從新加載,很是方便。後面運行其餘命令時,再打開一個終端(命令行)便可。

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

建立第一個自定義 Django App

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

Django App 的類別

Django App 通常分爲三大類(根據來源):

  • 內置:即 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 應用!可是如今這個應用尚未任何內容,咱們接下來將逐步完善這個應用。

理解視圖:業務邏輯的編寫

也許你已經注意到,經過訪問 localhost:8000/admin 已經能夠訪問後臺管理系統了(雖然會跳轉到登陸界面)。接下來,咱們也但願可以訪問到剛纔建立的 news 應用。所以,這一步中咱們將:

  • 在視圖(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 HttpResponse


def 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 path

from . import views

urlpatterns = [
    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 admin
from django.urls import path, include

urlpatterns = [
    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 代碼。須要注意的是,所支持的表達式僅支持如下形式(能夠自由組合):

<!-- 單個變量 -->
{{ variable }}

<!-- 獲取字典的鍵或對象的屬性 -->
{{ dict.key }}
{{ object.attribute }}

<!-- 獲取列表中的某個元素 -->
{{ list.0 }}
複製代碼

例如,模板這樣寫:

<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/news
touch 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 render


def 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.html
  • context:傳入模板的上下文對象,必須是一個字典,字典中的每一個鍵對應模板中的變量。這裏咱們弄了些假數據,僞裝是從數據庫裏面取來的。

再訪問 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 Blog
Blog.objects.all()

# 查詢單個模型
# 等價於 SELECT * FROM Blog WHERE ID=1
Blog.objects.get(id=1)

# 添加單個模型
# 等價於 INSERT INTO Blog (title, content) VALUES ('hello', 'world')
blog = Blog(title='hello', content='world')
blog.save()
複製代碼

有木有感受操做起來比 SQL 方便不少呢?

理解數據庫遷移

數據庫遷移是指將用 Django 定義的模型轉換成 SQL 代碼(即遷移文件),並在數據庫中進行建表操做(或更新表)。看下面這張圖就知道了:

通常的開發流程就是這樣:

  1. 用 Django 定義了一個新的數據模型
  2. makemigrations 命令建立遷移文件(存儲在子應用的 migrations 目錄裏面)
  3. migrate 命令執行遷移
  4. 在開發中發現第 1 步中定義的模型不完善,更新數據模型
  5. 跳轉到第 2 步,反覆循環

實現第一個數據模型

終於到了動手的環節。咱們首先定義數據模型 Post ,包括標題 title 字段和 content 字段,代碼以下:

from django.db import models


class 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 admin

from .models import Post

admin.site.register(Post)
複製代碼

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

點擊 Posts 一欄的 +Add 按鈕,開始添加新聞(內容隨意):

大概添加個兩三條新聞就差很少啦。你也能夠進一步探索後臺管理系統,包括修改新聞、添加用戶等等,均可以。

在視圖中添加數據查詢

最後,咱們在視圖中加入從數據庫中查詢的代碼:

from django.shortcuts import render

from .models import Post


def index(request):
    context = { 'news_list': Post.objects.all() }
    return render(request, 'news/index.html', context=context)
複製代碼

訪問網站首頁,能夠看到剛纔在後臺管理系統添加的新聞了:

大功告成!在這篇教程中,咱們完成了一個新聞發佈網站,而且能夠從後臺管理系統中添加新聞,最終展現到咱們的網站首頁上。

但願這篇教程可以讓你對 Django 最重要的一些概念和操做有了基本的瞭解。Django 還有不少不少的高級玩法,例如數據模型中的高級查詢、字段索引、更換數據庫等等,模板中的繼承機制、內部標籤等等,還有視圖中如何處理各種請求(POST、PUT等),咱們會在後續更多教程中逐一爲你們講解,不見不散!

想要學習更多精彩的實戰技術教程?來圖雀社區逛逛吧。

相關文章
相關標籤/搜索