Some notes on starting to use Django

Julia Evans

開始使用 Django 的一些筆記

哈囉!我最喜歡的事情之一,就是開始學習一項自己從未嘗試過、卻已經存在 20 多年的老派無聊技術。感覺真的很棒,因為我未來會遇到的每個問題,都已經被解決過上千次了,我只要輕鬆把事情完成就好。

我一直覺得學一套熱門的網頁框架,像是 Rails、Django 或 Laravel,應該會很酷,但一直都沒能真正付諸行動。不過幾個月前,為了做一個網站,我開始學習 Django,到目前為止還滿喜歡的,以下是一些簡短的筆記!

比 Rails 少一點魔法

我在 2020 年花了一些時間嘗試學習 Rails,雖然它很酷,我也很想喜歡上 Rails(Ruby 社群很棒!),但我發現如果把 Rails 專案擱置幾個月後再回來,就很難記得要怎麼完成任何事,因為(舉例來說)如果在你的 routes.rb 裡寫了 resources :topics,光看這一行並不會告訴你 topics 的路由是在哪裡設定的,你必須記得或去查詢慣例。

能夠把一個專案丟著好幾個月或好幾年,然後再回來繼續,對我來說非常重要(我所有的專案都是這樣運作的!),而 Django 對我來說感覺更容易,因為它的設定更明確。

在我這個小型的 Django 專案裡,感覺就只有 5 個主要檔案(設定檔除外):urls.pymodels.pyviews.pyadmin.pytests.py,如果我想知道其他東西(像是 HTML 樣板)在哪裡,通常都會在其中一個檔案裡被明確地參照。

內建的管理後台

在這個專案中,我想要一個管理介面來手動編輯或檢視資料庫中的一些資料。Django 有一個非常好用的內建管理介面,而且只要一點點程式碼就能自訂。

舉例來說,以下是我的其中一個 admin 類別的一部分,它設定了要在「清單」檢視中顯示哪些欄位、要針對哪個欄位搜尋,以及預設的排序方式。

@admin.register(Zine)
class ZineAdmin(admin.ModelAdmin):
    list_display = ["name", "publication_date", "free", "slug", "image_preview"]
    search_fields = ["name", "slug"]
    readonly_fields = ["image_preview"]
    ordering = ["-publication_date"]

有 ORM(物件關聯對映) 很有趣

過去我的態度是「ORM?誰需要那個?我自己寫 SQL 查詢就好了!」。不過到目前為止,我還滿享受 Django 的 ORM,而且我覺得 Django 用 __ 來表示 JOIN 的方式很酷,像這樣:

Zine.objects
    .exclude(product__order__email_hash=email_hash)

這個查詢涉及 5 個資料表:zineszine_productsproductsorder_productsorders。要讓它運作,我只需要告訴 Django 有一個 ManyToManyField 關聯了「orders」和「products」,以及另一個 ManyToManyField 關聯了「zines」和「products」,這樣它就知道如何連接 zinesordersproducts

我當然可以自己寫那個查詢,但寫 product__order__email_hash 需要打的字少很多,讀起來也感覺容易多了,而且老實說,我覺得要想出如何建構那個查詢(除了那些 join 之外還需要做一些其他事)可能要花上一段時間。

我完全不擔心 ORM 產生的查詢的效能,所以目前對 ORM 還滿興奮的,雖然我確定之後總會遇到讓人沮喪的地方。

自動遷移!

ORM 另一個很棒的地方就是遷移!

如果我在 models.py 中新增、刪除或修改一個欄位,Django 就會自動產生一個像 migrations/0006_delete_imageblob.py 這樣的遷移腳本。

我想如果有需要的話,我也可以編輯那些腳本,但到目前為止,我都是直接執行產生的腳本,完全沒做修改,運作得非常順利。真的感覺像魔法一樣。

我意識到,能夠輕鬆地執行遷移對現在的我來說很重要,因為我在摸索自己想要的運作方式時,還滿常更動資料模型的。

我喜歡文件

我以前有個壞習慣是從不看文件,但到目前為止,我非常喜歡我讀過的 Django 文件的那些部分。這並非偶然:Jacob Kaplan-Moss(傑可布·卡普蘭-莫斯)在 PyCon 2011 的演講中談到了 Django 的文件文化。

舉例來說,模型介紹就列出了使用 ORM 時你可能會想設定的最重要的常見欄位。

使用 SQLite

在嘗試維運 Postgres 卻搞不清楚狀況的糟糕經驗之後,我決定改用 SQLite 來跑我所有的小型網站。狀況好多了,而且我很喜歡只要執行 VACUUM INTO 然後複製產生的單一檔案就能完成備份的方式。

我一直按照這些說明在正式環境中使用 SQLite 搭配 Django。

我覺得應該沒問題,因為我預期這個網站一天最多只有幾百次寫入,遠少於Mess with DNS,後者有更多的寫入量而且運作良好(不過寫入是分散在 3 個不同的 SQLite 資料庫中)。

內建的電子郵件(還有更多)

Django 似乎非常「batteries-included」,這點我很喜歡——如果我想要 CSRF 防護,或是 Content-Security-Policy,或是想要寄送電子郵件,裡面全都有!

舉例來說,我想在開發模式下把 Django 寄出的電子郵件存成檔案(這樣就不會真的寄信給真實的使用者),這只需要一點點設定就好。

我只要在 settings/dev.py 中加入這樣:

EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
EMAIL_FILE_PATH = BASE_DIR / "emails"

然後在 settings/production.py 中這樣設定正式環境的電子郵件

EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.whatever.com"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = "xxxx"
EMAIL_HOST_PASSWORD = os.getenv('EMAIL_API_KEY')

這讓我覺得,如果我想要其他基本的網站功能,Django 裡很可能已經有簡單的內建做法可以實現。

設定檔還是感覺有點多

我對 settings.py 這個檔案還是有點敬畏:Django 的設定系統是透過在檔案中設定一堆全域變數來運作的,這讓我有點緊張……如果我把其中某個變數的名稱打錯了怎麼辦?我怎麼會知道?如果我打成 WSGI_APPLICATOIN = "config.wsgi.application" 而不是 WSGI_APPLICATION 會怎樣?

我想我已經習慣有 Python 語言伺服器在打錯字時提醒我,所以現在當無法依賴語言伺服器的支援時,就感覺有點不知所措。

就先到這裡!

我以前還沒有真正在專案中成功使用過網頁框架(目前我幾乎所有的網站不是單一的 Go 執行檔就是靜態網站),所以我很期待看看接下來的發展!

還有很多東西要學,我還沒有真正深入研究 Django 的表單驗證工具或認證系統。

感謝 Marco Rogers(馬可·羅傑斯)說服我給 ORM 一個機會。

(我們還在試驗在 Mastodon 上留言的系統!在 Mastodon 上的留言在這裡!告訴我你最喜歡的 Django 功能是什麼!)

原文由 Julia Evans 發布

本文章由 muse-spark-1.2-contributor 進行翻譯