本文為翻譯文章,內容請搭配 Django 1.3 版使用。
原文出處為 https://docs.djangoproject.com/en/1.3/intro/tutorial01/。
讓我們從範例開始吧。
透過這個教學將讓你體驗如何從頭到尾建立一個簡單的投票程式。
這個程式會包括兩部分:
- 一個可以讓人瀏覽、投票的公開網站。
- 一個管理後台,讓你可以新增、修改、刪除投票項目。
在此假設你已經安裝好 Django 了。你也可以在 Python 互動 Django 是在 Python 互動環境 (interactive interpreter) 中輸入 import django。如果指令成功執行、沒有發生任何錯誤,那麼 Django 就安裝好囉。
如何取得協助:
如果你在練習過程中遇到任何障礙,請到 django-users 發文、或在 irc.freenode.net 的 #django 頻道與其他 Django 使用者討論,也許有人能幫得上忙。
建立新專案
如果這是你首次使用 Django,你得先瞭解一些初始化的步驟。也就是說,你需要自動產生一些建立 Django 專案的程式碼,這些程式碼是一堆 Django 設定的集合,包括了資料庫設定、Django 本身的設定選項以及應用程式的相關設定。
透過命令列的 cd 指令切換到你儲存程式的資料夾,接著執行指令 django-admin.py startproject mysite。這將在你所在的資料夾建立 mysite 資料夾。
不同版本的指令也許會有所不同
如果你透過各版本的 Linux 套件管理員(例如 apt-get 或 yum)安裝 Django,django-admin.py 也許會換個名字叫作 django-admin。在這份文件後續出現的每個指令你可以省略掉 .py。
Mac OS X 權限
如果你用的是 Mac OS X,當你試著要執行 django-admin.py startproject 時,你也許會看到「權限不足 (permission denied)」的訊息。這是因為在像 OS X 這樣的 Unix 系統中,檔案在執行之前必須被標記為「可執行的 (executable)」。進行這個設定的方式是,打開 Terminal.app,並瀏覽(使用 cd 指令)找出 django-admin.py 安裝的資料夾,接著執行指令 chomd +x django-admin.py。
備註
你得避免專案名稱和在 Python 內建元件或 Django 元件撞名。這更意味著你應該避免使用像 django(這會和 Django 本身衝突)或是 test(會和 Python 內建套件衝突)這樣的命名。
如果你透過 python setup.py 安裝 Django,那麼 django-admin.py 應該在你的系統路徑上。如果它不在你的目錄裡,你可以在 site-packages/django/bin 找到('site-packages' 是你的 Python 所安裝的目錄)。考慮在像 /usr/local/bin 之類的地方將你的路徑指向 (symlinking) django-admin.py。
這些程式碼該放在哪?
如果你學過 PHP,你也許會習慣把程式碼放在網站伺服器的文件根目錄(比方說 /var/www)。不過在 Django 你就不用這樣做了。把什麼 Python 原始碼都扔上你的網站伺服器文件根目錄,可不是什麼好主意,因為這可能造成別人可能在網站上瀏覽你的原始碼的風險。就安全考量來看這可不太妙。
把你的原始碼放在某個不在文件根目錄的資料夾,比方說 /home/mycode。
我們來看看 startproject 建立了些什麼:
mysite/
__init__.py
manage.py
settings.py
urls.py
這些檔案分別是:
- __init__.py: 一個空白檔案,告訴 Python 這個目錄應該被視為是 Python 套件。(如果你是個 Python 初學者,可以閱讀 Python 官方文件,瞭解更多有關於套件的資訊。)
- manage.py: 一個命令列工具,讓你能以不同方式與這個 Django 專案互動。你可以在 django-admin.py and manage.py 閱讀所有關於 manage.py 的細節。
- settings.py: 這個 Django 專案的設定、配置。Django settings 說明了這個設定檔的運作方式。
- urls.py: 這個 Django 專案的 URL 宣告;是你的 Django 網站的「目錄」。你可以在 URL dispatcher 取得更多與 URL 相關的資訊。
開發伺服器
讓我們來驗證一下它可以運作吧。切換到 mysite 資料夾(如果你還沒切過去),然後執行指令 python manage.py runserver。你可以看到命令列視窗出現下列輸出:
Validating models...
0 errors found.
Django version 1.0, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
你已經啟動了 Django 開發伺服器,這是個完全以 Python 撰寫的輕量型網站伺服器。Django 開發團隊把它包進 Django 裡頭,這麼一來你就可以快速開發,在你準備要上線之前都不必去設定正式主機的設定(像 Apache)。
這是個提醒你的好時機──千萬別在任何正式上線環境使用類似這樣的伺服器。僅限開發使用。(Django 開發團隊設計的是一個網站框架,可不是網站伺服器噢。)
現在伺服器開始運作啦,從你的瀏覽器看看 http://127.0.0.1:8000/。你會看到一個甜美輕柔的淡藍色 "Welcome to Django" 頁面。開發伺服器正常運作囉!
改變埠號 (port)
預設的情況下,runserver 指令會在內部 IP 的 8000 port 啟動開發伺服器。
如果你想改變伺服器埠號,就把埠號加進去命令列參數裡。比方說呢,下列指令會啟動一個在 8080 port 上的伺服器:python manage.py runserver 8080如果你想改變伺服器 IP,就把 IP 和 port 寫在一起。如果要讓所有 public IP 可以連上來(如果你要在其他電腦上顯示你的成果時會用得到),就這樣做:python manage.py runserver 0.0.0.0:8000完整的開發伺服器文件請參考 runserver 一節。
資料庫設定
現在來編輯 settings.py。這是個一般的 Python 模組,以模組級變數 (module-level variables) 呈現 Django 設定值。改變 DATABASES 的 'default' 項目中的下列值,以符合你的資料庫連線設定:
- ENGINE -- 可以是 'django.db.backends.postgresql_psycopg2', 'django.db.backends.mysql' 或 'django.db.backends.sqlite3'. 其他後端也行得通。
- NAME -- 你的資料庫名稱。如果你使用 SQLite,資料庫會是你電腦上的一個檔案;在這種情況下,NAME 應該是資料庫檔案的完整的絕對路徑(包括檔名)。如果該檔案不存在,它會在你第一次同步資料庫時一併自動建立。(詳見後續說明)
在設定路徑時,一定要用斜線,即使是在 Windows 上也是一樣。(例如:C:/homes/user/mysite/sqlite3.db) - USER -- 你的資料庫使用者名稱(SQLite 不必設)。
- PASSWORD -- 你的資料庫密碼(SQLite 不必設)。
- HOST -- 你的資料庫主機。若你的資料庫伺服器是安裝在同一台實體機器上,這個設定就保持空白(SQLite 不必設)。
如果你是個資料庫新手,我們會建議你用 SQLite(ENGINE 設定為 'django.db.backends.sqlite3')。SQLite 內建於 Python 2.5 與其之後更新的版本,你就不用再安裝任何東西。
備註
如果你用的是 PostgreSQL 或 MySQL,在此要確認你已經建立了資料庫。在你的資料庫互動介面裡,執行 "CREATE DATABASE database_name;" 以建立資料庫。
如果你用的是 SQLite,你不必事先建立任何東西──資料庫檔案會在必要時自動建立。
當你編輯 settings.py 時,留意一下檔尾的 INSTALLED_APPS 設定。這變數包括了所有位於目前 Django 實體中的 Django 應用程式的名稱。應用程式可以在多個專案裡使用,你可以打包、發佈這些應用程式給其他人,讓其他人能在他們的專案裡使用。
預設情況下,INSTALLED_APPS 包括了下列應用程式(皆由 Django 提供):
- django.contrib.auth -- 認證系統。
- django.contrib.contenttypes -- 內容類別 (content types) 框架。
- django.contrib.sessions -- session 框架。
- django.contrib.sites -- 管理多個站台與單一 Django 安裝的框架。
- django.contrib.messages -- 訊息 (messaging) 框架。
- django.contrib.staticfiles -- 管理靜態檔案的框架。
一般情況下,預設環境都附有這些應用程式。
每一個應用程式都用到至少一個資料表,所以我們得在用到這些應用程式前先在資料庫建立這些資料表。為了完成這項前置作業,我們執行下列指令:
python manage.py syncdb
syncdb 指令根據 INSTALLED_APPS 設定與你的 settings.py 設定,建立所有必備的資料表。你會看到每個資料表建立完成的訊息,也會有提示訊息詢問你是否要建立認證系統中的 superuser 帳戶。依序完成這些事。
如果你有興趣的話,你可以執行你的資料庫的命令列工具,並輸入 \dt (PostgreSQL)、SHOW TABLES (MySQL)、.shema (SQLite) 列出 Django 建立的資料表。
簡化
如同先前提過的,一般在預設情況下都自動引用了應用程式,不過不是每個人都用得到這些東西。如果你用不著它們,可以在執行 syncdb 之前,隨時註解掉或刪除 syncdb 指令只建立 INSTALLED_APPS 裡頭的應用程式所需的資料表。
建立模組
現在你的環境(一個「專案」)已經建置好囉,你已經準備好開工啦。
每個你撰寫的 Django 應用程式由 Python 套件(位於某個你的 Python 路徑上)組成,遵循一定的規範。Django 本身有個功能,可以自動產生基本的應用程式資料夾結構,所以你只要專心寫你的程式碼就好,不必管要開哪些目錄。
專案 (Projects) vs. 應用程式 (apps)
專案和應用程式有什麼不同呢?一個應用程式就是一個處理某些事的網頁應用程式,比方說部落格、簡易投票應用程式的公開記錄資料庫……等等;一個專案是特定網站的設定值與應用程式的集合。專案包括了許多的應用程式;應用程式可以身處於多個專案之中。
你的應用程式可以放在 Python 路徑上的任何地方。在這份教學裡,我們將我們的投票應用程式建立在 mysite 資料夾。
確認你已位於 mysite 資料夾後,輸入下列指令來建立你的應用程式:
python manage.py startapp polls
這樣就建立了一個 polls 資料夾,結構長成這樣:
polls/
__init__.py
models.py
tests.py
views.py
這個目錄結構就是用來儲存投票程式的。
撰寫 Django 資料庫網站應用程式的第一步就是定義你的模組──也就是你的資料庫架構以及其中的詮釋資料 (metadata)。
原理
你的資料唯一且明確的資料來源就是模組 (model)。包括你的資料儲存時的必要欄位與行為。Django 依循 DRY 準則。其目的是在某個地方定義你的資料模組,並透過這個模組自動產生一些東西。
在我們的簡易型投票程式裡,我們會建立兩個模組:投票 (polls) 與選項 (choices)。投票包括了問題與公告日期;選項包括兩個欄位:選項的描述文字與得到的合計票數。每個選項都和投票相關。
這些概念可以由簡單的 Python 類別實現。編輯 polls/models.py 檔案,內容如下:
from django.db import models
class Poll(models.Model):
question = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice = models.CharField(max_length=200)
votes = models.IntegerField()
原始碼很簡單。每個模組都是 django.db.models.Model 這個類別的子類別。每個模組都有一些它自己的類別變數,每個模組裡的類別變數又都能對應到資料庫的特定欄位。
每個欄位以欄位類別實體表示──比方說,CharField 是字元欄位,DateTimeField 是日期與時間欄位。這會讓 Django 知道每個欄位裡保存了什麼類別的資料。
每個欄位實體的名稱(例如:question 或 pub_date)就是欄位的名稱,以機讀格式儲存。你可以在 Python 原始碼裡使用這些值,你的資料庫會取用它們作為欄位名稱。
你可以利用第一個選填參數指定一個可供人工判讀的名稱。它用在 Django 的一對內省部分 (introspective parts),也兼作為說明文件之用。如果這個欄位未設定,Django 會使用機讀名稱。在這個範例裡,我們只定義了人工判讀的名稱 Poll.pub_date。對這個模組裡的其他部分而言,這部分的機讀名稱就足以作為人工判讀名稱了。
部分欄位類別有其必要元素。比方說,CharField 必須給定一個 max_length。它不僅用在資料庫結構,還用在驗證,我們後面也會談到。
最後,請留意使用外鍵定義的關係。這讓 Django 知道每個 Choice 會和一個 Poll 產生關聯。Django 支援所有常見資料庫的關聯模式:多對一、多對多、一對一。
啟用模組
這一小段模組程式碼卻給了 Django 大量的訊息。有了它,Django 可以:
- 建立這支應用程式的資料庫結構(CREATE TABLE 語法)。
- 建立取用 Poll 與 Choice 物件的 Python database-access API。
但我們得先讓專案知道,polls 應用程式已經安裝好了。
原理
Django 應用程式是「可插拔 (pluggable)」的:你可以在多個專案中使用同一支應用程式,同時你還可以發布應用程式,因為應用程式不會被綁死在特定的 Django 安裝 (installation) 裡。
再次編輯 settings.py 這支檔案,變更 INSTALLED_APPS 的設定字串使之包括了 'polls',完成設定後的內容如下:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'polls'
)
現在 Django 已經得知 polls 應用程式被引用了。我們再執行另一個指令:
python manage.py sql polls
你應該可以看到類似以下的內容(用來建立 polls 應用程式的 CREATE TABLE SQL 語法):
BEGIN;
CREATE TABLE "polls_poll" (
"id" serial NOT NULL PRIMARY KEY,
"question" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
CREATE TABLE "polls_choice" (
"id" serial NOT NULL PRIMARY KEY,
"poll_id" integer NOT NULL REFERENCES "polls_poll" ("id"),
"choice" varchar(200) NOT NULL,
"votes" integer NOT NULL
);
COMMIT;
請注意以下幾點:
- 實際的輸出取決於你所使用的資料庫。
- 資料表名稱是根據應用程式 (polls) 的名稱與小寫的模組名稱 (poll, choice) 自動產生的。(你可以改寫這個行為)
- 主鍵 (ID) 是自動加上去的。(你也可以改寫這個行為)
- 依慣例,Django 會在外鍵欄位的名稱加上 "_id"。當然啦,你也可以改寫這行為。
- 外鍵關聯是由 REFERENCES 語句明確宣告。
- 這是針對你正在使用的資料庫,所以資料庫的特有欄位類別,例如 auto_increment (MySQL), serial (PostgreSQL), 或 integer primary key (SQLite) 都會自動為您處理好。引用欄位名稱時也是自動為您處理好(例如:應該使用雙引號或單引號)。這個教學的作者使用的是 PostgreSQL,所以範例輸出的就是 PostgreSQL 語法。
- SQL 指令並未實際在你的資料庫中執行──這只是把結果印出在螢幕上,讓你看看 Django 認為怎樣的 SQL 是必要的。如果你要執行這些 SQL,你得把這些 SQL 複製、貼上到你的資料庫互動介面上。不過等一下我們就會看到 Django 提供了一個更簡單的方法來送交 SQL 指令給資料庫。
如果你有興趣的話,還可以執行下列指令:
- python manage.py validate -- 確認你的模組裡有沒有任何錯誤。
- python manage.py sqlcustom polls -- 輸出為應用程式而定義的自訂 SQL 語法(比方說修改資料表或約束條件設定)。
- python manage.py sqlclear polls -- 在需要時根據你的資料庫中已存在的資料表,輸出應用程式所需要的 DROP TABLE 語法。
- python manage.py sqlindexes polls -- 輸出應用程式所需的 CREATE INDEX 語法。
- python manage.py sqlall polls -- 合併所有 sql, sqlcustom, sqlindex 的 SQL 語法。
檢視這些指令的輸出,有助於你瞭解在這個機制下實際上發生了什麼事。
現在,再次執行 syncdb 以便在你的資料庫裡建立那些模組的資料表:
python manage.py syncdb
syncdb 指令會根據 INSTALLED_APPS 裡的所有應用程式,找出還沒在資料庫裡建檔的應用程式,在你的資料庫上執行 'sqlall' 的 SQL 指令。這會為你上次執行 syncdb 後加入到專案裡的所有應用程式,建立所有的資料表、初始化資料與索引。你可以隨心所欲的執行 syncdb,反正它只會建立尚不存在的資料表。
閱讀 django-admin.py,可以全盤瞭解 manage.py 功能可以做哪些事。
使用 API!
現在,我們來進入 Python 互動式命令列環境、試試 Django 送你的免費 API 吧。使用下列指令來啟動 Python 命令列:
python manage.py shell
我們執行這句指令、而不是單單只輸入 "python",因為 manage.py 會為你設置系統環境。「設定環境」包括了兩件事:
- 在 sys.path 設定 polls。為了增加彈性,在此專案使用到的數個 Django 參照會以 Python 的點路徑 (dotted-path) 方式表示(例如:'polls.models')。為了能正常運作,polls 套件必須設在 sys.path。
我們已經看到一個範例:INSTALLED_APPS 設定就是個以點路徑表示的套件列表。 - 設定 DJANGO_SETTINGS_MODULE 環境變數,這變數可以讓 Django 取得你的 settings.py 檔案的路徑。
略過 manage.py
如果你不想用 manage.py,那也沒關係。只要確定 mysite 和 polls 都在 Python 路徑的根節點就好(例如:import mysite 和 import polls 可正常運作無誤),同時在 mysite.settings 設定 DJANGO_SETTINGS_MODULE 環境變數。
欲知詳情請參考 django-admin.py。
進入命令列模式後,瀏覽資料庫 API:
>>> from polls.models import Poll, Choice # Import the model classes we just wrote.
# 目前系統裡還沒有任何的投票
>>> Poll.objects.all()
[]
# 建立一個新的 Poll
>>> import datetime
>>> p = Poll(question="What's up?", pub_date=datetime.datetime.now())
# 把物件存進資料庫。你得明確地呼叫 save()。
>>> p.save()
# 現在它有了 ID 了。記住,這也許叫作 "1L" 而不是 "1"(取決於你使用的資料庫)。
# 這也沒什麼,只代表你的資料庫後端傾向回傳 Python 長整數型態的整數。
>>> p.id
1
# 透過 Python 屬性來取得資料庫欄位。
>>> p.question
"What's up?"
>>> p.pub_date
datetime.datetime(2007, 7, 15, 12, 00, 53)
# 修改屬性值,呼叫 save()。
>>> p.pub_date = datetime.datetime(2007, 4, 1, 0, 0)
>>> p.save()
# objects.all() 顯示所有資料庫裡的投票資料。
>>> Poll.objects.all()
[<Poll: Poll object>]
且慢。<Poll: Poll object> 這樣的呈現結果,完全無助於瞭解物件本身。我們來改一下 polls 模組(在 polls/models.py 這個檔案裡),增加 __unicode__() 方法到 Poll 與 Choice 類別裡:
class Poll(models.Model):
# ...
def __unicode__(self):
return self.question
class Choice(models.Model):
# ...
def __unicode__(self):
return self.choice
在你的模組裡加上 __unicode__() 是很重要的,不僅為了你在命令列模式裡能清楚思考,也是為了在整個 Django 自動產生的管理介面裡物件中的物件呈現著想。
為什麼用 __unicode__(),而不用 __str__()?
如果你很熟 Python,你可能會習慣在你的類別裡加上 __str__() 方法、而非 __unicode__()。在這邊我們用了 __unicode__(),是因為 Django 模組預設會以 Unicode 處理。所有存在你的資料庫裡的資料都會被轉成 Unicode 後回傳。
Django 模組預設的 __str__() 方法會呼叫 __unicode__() 並將結果轉換為 UTF-8 字串陣列。也就是說呢,unicode(p) 會回傳 Unicode 字串,而 str(p) 會回傳一般字串(字串中的每個字元會編碼為 UTF-8)。
如果上述對你來說是一團亂碼,那麼只要記住在你的模組裡加上 __unicode__() 就對了。運氣好的話,一切會為了你而正常運轉的。
請注意這些都是一般的 Python 方法。我們來增加個示範用的自訂方法:
import datetime
# ...
class Poll(models.Model):
# ...
def was_published_today(self):
return self.pub_date.date() == datetime.date.today()
更多 import datetime 的延伸內容,請參考 Python 標準 datetime 模組。
儲存這些變更,開啟一個新的 Python 互動視窗、再次執行 manage.py 指令:
>>> from polls.models import Poll, Choice
# 確定新增的 __unicode__() 可以正常運作
>>> Poll.objects.all()
[<Poll: What's up?>]
# Django 提供了一個完整的資料庫查找 API,完全由關鍵字參數驅動
>>> Poll.objects.filter(id=1)
[<Poll: What's up?>]
>>> Poll.objects.filter(question__startswith='What')
[<Poll: What's up?>]
# 取得投票年份在 2007 的資料
>>> Poll.objects.get(pub_date__year=2007)
<Poll: What's up?>
>>> Poll.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Poll matching query does not exist.
# 通常會以主鍵搜尋,所以 Django 提供一個捷徑來進行主鍵明確搜尋。
# 下列內容和 Poll.objects.get(id=1) 是一樣的。
>>> Poll.objects.get(pk=1)
<Poll: What's up?>
# 確定我們的自訂方法可以正常運作。
>>> p = Poll.objects.get(pk=1)
>>> p.was_published_today()
False
# 讓每個投票有兩個選項。create 建立了新的 choice 物件,執行 INSERT 語法,
# 增加 choice 到可選擇的選項中,並回傳一個新的 Choice 物件。
# Django 建立了一個集合來維持「另一方面」的外鍵關聯(例如:投票中的選項們),
# 可透過 API 取用。
>>> p = Poll.objects.get(pk=1)
# Display any choices from the related object set -- none so far.
>>> p.choice_set.all()
[]
# 建立三個 choices。
>>> p.choice_set.create(choice='Not much', votes=0)
<Choice: Not much>
>>> p.choice_set.create(choice='The sky', votes=0)
<Choice: The sky>
>>> c = p.choice_set.create(choice='Just hacking again', votes=0)
# Choice 物件有方法可以取得它們相關聯的 Poll 物件。
>>> c.poll
<Poll: What's up?>
# 反之亦然,Poll 物件可以取得 Choice 物件。
>>> p.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> p.choice_set.count()
3
# 這個 API 依你所需自動追蹤關聯。
# 使用雙下劃線切割關聯。
# 你想切幾層就幾層,沒有限制。
# 找出 pub_date 屬於 2007 年的投票的所有 Choice。
>>> Choice.objects.filter(poll__pub_date__year=2007)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
# 使用 delete() 刪除一個選項
>>> c = p.choice_set.filter(choice__startswith='Just hacking')
>>> c.delete()
想知道更多模組間的關聯,請參考 Accessing related objects。想瞭解更多如何透過 API 使用雙下劃線 (double underscores) 進行欄位查找 (field lookups),請參考 Field lookups。完整的資料庫 API 細節,請參考 Database API reference。
當你熟悉了這個 API,接著來看看這個教學的第二章,讓 Django 的自動管理介面執行起來吧。
本文為翻譯文章,內容請搭配 Django 1.3 版使用。
原文出處為 https://docs.djangoproject.com/en/1.3/intro/tutorial01/。
留言列表