天天看點

Django 最佳實踐Django 最佳實踐 - 中文版 (2009-06-17)Django 最佳實踐

Django 最佳實踐 - 中文版 (2009-06-17)

譯者 (yospaly) 前言

Django 最佳實踐 (django-best-practices) 是 django-reusable-app-docs 的一個分支項目, 它在原有項目的理念上進行了擴充, 建立了一套關于 Django Web 開發方面的 “最佳實踐” 規則, 這些理念超出了官方文檔的讨論範圍.

這份文檔由一系列準則組成, 圍繞這如何建立便于維護, 代碼幹淨, 結構清晰, 友善複用, 易于部署的 Django 項目. 對于初學者, 它是一份不可多得指南, 如果不知道從何下手, 按照文檔說做能很快規範起來; 對于經驗豐富 Django 達人, 它也有一定的參考價值, 可以據此來建立自己的最佳實踐準則.

遺憾的是本人理工科出身, 水準有限, 翻譯中規中矩, 隻能勉強表達出原文傳遞的資訊. 還有小部分尚不解其意 (文中有備注) :)

原文是多頁面方式, 不過 實踐 每個規則的内容并不太多, 打散成多頁面反而浏覽不友善. 是以我把它們全合并到單個頁面中, 除此之外, 沒做其它改動.

原文和譯文的源檔案均使用 reStructuredText 格式, 可以用 Sphinx 轉換成 HTML 等格式的文檔.

  • 中文最新版本線上文檔
  • 中文版項目首頁
  • 作者的項目聲明
  • 英文最新版本線上文檔

注解

中文版力求保持和英文版同步更新. 目前版本 2009-06-17 11:32:35

Django 最佳實踐

這是一份關于開發和部署 Django Web 架構 的動态文檔 (會随時更新). 這些準則不應該被認為是 絕對正确 或 唯一 使用 Django 的方法, 應該說這些最佳實踐是我們使用架構多年來積累的經驗.

本項目是 django-reusable-app-docs 項目 的一個分支, 這個優秀的項目是由 Brian Rosner 和 Eric Holscher 建立的, 是關于如何開發和維護可複用 Django apps 方面的最佳實踐準則.

注解

這份文檔的源碼放在 GitHub django-best-practices , 可以用 Sphinx 轉換成多種文檔格式

代碼風格

一般而言, 代碼應該幹淨, 簡明, 易讀. The Zen of Python (PEP 20) 是 Python 編碼實踐的權威介紹.

  • 盡可能合理的遵守 Style Guide for Python Code (PEP 8).
  • 遵守 Django coding style.

Django 應用 (app)

如何釋出我的 app ?

Django 應該使用使用标準的 Python Package Index 即 Pypi 和 Cheese Shop. 我寫過一篇關于如何輕松打包和上傳 app 到 Pypi 的 教程.

如果你上傳 app 到 Pypi, 建議最好在你的項目名前加上 “django-” 字首.

(yospaly: 以下不解其意, 望達人指點) Also note, that when below when we refer to the default place for something as a file, that also means that you can make a directory of that same name; as per normal python.

文檔

  • 放在和 APP 目錄同級的 docs 目錄中 (你的 app 應該有上級目錄的吧?)
  • 可以包含模闆, 供使用者參考

什麼是可複用 app?

一個 Django app, 一個能夠輕松嵌入到 project 的 app, 提供一個非常明确的功能. 它們應該專注并遵循 Unix 哲學 – “做一件事并把它做好”. 更多相關資訊請參考 James Bennett 的 Djangocon talk.

Application 子產品

(yospaly: 以下所有大寫單詞, 如: APP, MODEL 等, 替換成你項目中真實的 app 名或 model 名.)

Admin

  • 非必須
  • 放在 APP/admin.py 檔案中
  • Admin 的 MODEL 類命名為 MODELAdmin

上下文處理器

  • 放在 APP/context_processors.py 檔案中

内容源

  • 放在 APP/feeds.py 檔案中

表單

  • 放在 APP/forms.py 檔案中

Managers

  • 放在 APP/managers.py 檔案中

中間件

  • 放在 APP/middleware.py 檔案中
  • 實作盡可能少的任務

模型

  • 放在 APP/models (.py 檔案中或目錄下)
  • 遵循 Django’s 模型約定

模闆

  • 放在 APP/templates/APP/template.html 檔案中

為了盡量标準化 Django 模闆區塊 (block) 名稱, 我建議通常情況下使用以下區塊名稱.

  • {% block title %}

這個區塊用來定義頁面的标題. 你的 base.html 模闆很可能要在這個 tag 之外定義站點名字 (Site’s name) (即便使用了 Sites 架構), 以便能夠放在所有頁面中.

  • {% block extra_head %}

我認為這是個非常有用的區塊, 很多人已經以某種方式在使用了. 很多頁面經常需要在 HTML 文檔頭添加些資訊, 比如 RSS 源, Javascript, CSS, 以及别的應該放在文檔頭的資訊. 你可以, 也很可能将會, 定義另外專門的區塊 (比如前面的 title 區塊) 來添加文檔頭的其它部分的資訊.

  • {% block body %}

這個 tag 用來包含頁面的整個 body 部分. 這使得你在 app 中建立的頁面能夠替換整個頁面内容, 不僅僅是正文内容. 這種做法雖不常見, 但當你需要時, 它确實是一個非常友善的 tag. 你可能還沒注意到, 我一直盡可能的使 tag 名字和 HTML 标簽名稱保持一緻.

  • {% block menu %}

你的菜單 (導航欄) 應該包含在這個區塊中. 它是針對站點級的導航, 不是每個頁面專屬的導航菜單.

  • {% block content %}

這個區塊用來放置頁面正文内容. 任何頁面正文内容都可能不一樣. 它不包含任何站點導航, 資訊頭, 頁腳, 或其它任何屬于 base 模闆的東東.

其它可能的區塊
  • {% block content_title %}

用來指定 content 區塊的 “title”. 比如 blog 的标題. 也可以用來包含 content 内的導航 (譯注: 比如提綱), 或其它類似的東東. 大緻都是些頁面中并非主要内容的東東. 我不知道這個區塊是否應該放到 content tag 内, 并且對應于前面建議的 content tag, 是不是還需要一個 main_content 區塊.

  • {% block header %} {% block footer %}

任何每個頁面都可能修改的文本區域的頁面和頁腳.

  • {% block body_id %} {% block body_class %}

用來設定 HTML 文檔 body 标簽的 class 或 id 屬性. 在設定樣式或其它屬性時非常有用.

  • {% block [section]_menu %} {% block page_menu %}

這是對應于之前建議的 menu 區塊. 用來導航一個章節或頁面.

模闆标簽

  • 放在 APP/templatetags/APP_tags.py 檔案中
推薦的模闆标簽文法
  • as (Context Var): This is used to set a variable in the context of the page
  • for (object or app.model): This is used to designate an object for an action to be taken on.
  • limit (num): This is used to limit a result to a certain number of results.
  • exclude (object or pk): The same as for, but is used to exclude things of that type.

測試

  • 放在 APP/tests (.py 檔案或目錄) 中
  • Fixtures 放在 APP/fixtures/fixture.json 檔案中
  • 通常隻須重寫 Django 的 testcase

URLs

  • 放在 APP/urls (.py 檔案或目錄) 中
  • 需要設定 name 屬性以便能夠被反查; name 屬性設定成 APP_MODEL_VIEW 的格式, 比如 blog_post_detail 或 blog_post_list.

視圖

  • 放在 APP/views (.py 檔案或目錄) 中
  • 可以是任何可調用的 python 函數.
  • 視圖參數應提供合理的預設值, 并易于定制:

範例:

def register(request, success_url=None,
         form_class=RegistrationForm
         template_name='registration/registration_form.html',
         extra_context=None):      

Django Projects (項目)

推薦的布局

example.com/
   README
   settings.py
   urls.py
   docs/
       This will hold the documentation for your project
   static/
       -In production this will be the root of your MEDIA_URL
       css/
       js/
       images/
   tests/
       - Project level tests (Each app should also have tests)
   uploads/
       - content imgs, etc
   templates/
       - This area is used to override templates from your reusable apps
       flatpages/
       comments/
       example/
       app1/
       app2/      

什麼是 Django Project?

Django 中的 project 指的是一個包含設定檔案, urls 連結, 以及一些 Django Apps 集合的簡單結構. 這些東東可以是你自己寫的, 也可以是一些包含在你的 project 内的第三方代碼.

Project 子產品

設定

放在 [PROJECT]/settings.py 檔案中

使用相對路徑

import os
DIRNAME = os.path.dirname(__file__)

MEDIA_ROOT = os.path.join(DIRNAME, 'static')
      

具體環境相關的設定使用 local_settings.py 檔案, 并在 settings.py 檔案結尾導入它.

try:
    from local_settings import *
except ImportError:
    pass
      

URLs

  • 放在 PROJECT/urls.py 檔案中
  • 應包含最少的邏輯代碼, 多數情況下隻作為一個指針, 指向你 apps 各自的 URL 配置.

部署

Project 的環境初始化

檔案系統布局

注解

本文檔嚴重偏向 Unix 風格的檔案系統, 要在其它作業系統上使用需要做些額外的修改.

Virtualenv 對于 Python 項目來說是必須的. 它提供一個隔離不同 Python 運作環境的方法. 典型的, 我們在 /opt/webapps/<site_name> 部署生産環境站點, 在 ~/webapps/<site_name> 目錄部署我們的開發環境站點. 每個 project 有它自己的 virtualenv, virtualenv 還充當 project 所有相關代碼的根目錄. 我們使用 pip 為 virtualenv 添加必要的包.

引導過程看上去是這樣的:

cd /opt/webapps
virtualenv mysite.com
cd mysite.com
pip install -E . -r path/to/requirements.txt
source bin/activate
      

小技巧

友善起見, 你可以在你的 virtualenv 根目錄中建立 Django project 的符号連結. 符号連結的名字無所謂, 因為你的 project 已經在 Python 搜尋路徑中. 通過給你所有的 projects 起同樣的符号連結名, 你可以使用一些 友善的 bash 函數以節省時間.

打包

成功部署的關鍵之一是, 保證你開發環境下的軟體盡可能接近部署環境下的軟體. Pip 提供了一個簡單的重制方法, 讓你在任何系統上都能非常一緻的部署 Python 項目. 任何需要第三方庫的 app 都應該包含一個名為 requirements.txt 的 pip 規格檔案. Projects 應到負責彙集所有 app 的規格檔案, 并在根據需要添加其它規格.

你的規格檔案中要包含些什麼

我們的經驗是, 任何應用程式, 隻要你的作業系統預設沒附帶. 唯一需要從我們的規格檔案中剔除的幾個包是 PIL, 資料庫驅動和其它 pip 不能安裝的包. 這些被剔除的規格放在 project’s README 檔案中加以說明.

伺服器

注解

部署架構很大程度上取決于站點的流量. 下面描述的設定對我們來說, 在大多數情況下工作的最好.

我們基于 Linux 和 PostgreSQL 後端資料庫部署 Django, Nginx 程序作為前端代理, 處在其後的是 Apache 和 mod_wsgi.

Nginx

Nginx 是一個非常優秀的前端伺服器, 速度快, 穩如磐石, 并且資源占用很少. 以下是一個典型的 Nginx 站點配置:

它都做些什麼?

第一段告訴 Nginx 去哪裡找托管了 Django 站點的伺服器. 第二段把所有來自 www.domain.com 的請求重定向到 domain.com, 這樣所有資源就都隻有一個 URL 能被通路到. 最後一段承擔了所有工作. 它告訴 Nginx 檢查 /var/www/domain.com 中是否存在被請求的檔案. 如果存在, 它傳回該檔案, 否則, 它将把請求轉發給 Django 站點.

警告

yospaly 注

以下涉及 Apache 的部分均未作翻譯, 我們強烈建議使用 Nginx/Lighttpd + SCGI/FastCGI/HTTP 的方式, 盡量不要使用繁瑣的 Apache + mod_wsgi.

SSL

Another benefit to running a frontend server is lightweight SSL proxying. Rather than having two Django instances running for SSL and non-SSL access, we can have Nginx act as the gatekeeper redirecting all requests back to a single non-SSL Apache instance listening on the localhost. Here’s what that would look like:

You can include this code at the bottom of your non-SSL configuration file.

小技巧

For SSL-aware Django sites like Satchmo, you’ll need to “trick” the site into thinking incoming requests are coming in via SSL, but this is simple enough to do with a small addition to the WSGI script we discuss below.

Apache

We run the Apache2 Worker MPM with mod_wsgi in daemon mode. The default settings for the MPM Worker module should be sufficient for most environments although those with a shortage of RAM may want to look into reducing the number of servers spawned. Since Nginx will be listening for HTTP(S) requests, you’ll need to bind Apache to a different port. While you’re at it, you can tell it to only respond to the localhost. To do so, you’ll want to edit the Listen directive

Listen 127.0.0.1:9000
      

With Apache up and running, you’ll need an Apache configuration and WSGI script for each site. A typical Apache configuration for an individual site looks like this:

小技巧

In a perfect world, your app would never leak memory and you can leave out the maximum-requests directive. In our experience, setting this to a high number is nice to keep Apache’s memory usage in check.

警告

This will default to a single process with 15 threads. Django is not “officially” thread safe and some external libraries (notably a couple required for django.contrib.gis) are known to not be thread safe. If needed the threads and processes arguments can be adjusted accordingly.

It links to the WSGI script within the project directory. The script is just a few lines of Python to properly setup our environment.