讓我們通過例子來學(xué)習(xí)。
在本教程中,我們將引導(dǎo)您創(chuàng)建一個基本的投票應(yīng)用。
它將包含兩部分:
我們假設(shè)你已經(jīng) 安裝了 Django 。你可以運行以下命令來驗證是否已經(jīng)安裝了 Django 和運行著的版本號:
python -c "import django; print(django.get_version())"
你應(yīng)該看到你安裝的 Django 版本或一個提示你 “No module named django” 的錯誤。此外,還應(yīng)該檢查下你的版本與本教程的版本是否一致。 若不一致,你可以參考 Django 版本對應(yīng)的教程或者更新 Django 到最新版本。
請參考 如何安裝 Django 中的意見先刪除舊版本的 Django 再安裝一個新的。
在哪里可以獲得幫助:
如果您在學(xué)習(xí)本教程中遇到問題,請在 django-users 上發(fā)貼或者在 #django on irc.freenode.net 上與其他可能會幫助您的 Django 用戶交流。
如果這是你第一次使用 Django ,那么你必須進行一些初始設(shè)置。也就是通過自動生成代碼來建立一個 Django 項目 project – 一個 Django 項目的設(shè)置集,包含了數(shù)據(jù)庫配置、 Django 詳細選項設(shè)置和應(yīng)用特性配置。
在命令行中,使用 cd 命令進入你想存儲代碼所在的目錄,然后運行以下命令:
django-admin.py startproject mysite
這將在當(dāng)前目錄創(chuàng)建一個 mysite 目錄。如果失敗了,請查看 Problems running django-admin.py.
Note
你需要避免使用 python 保留字或 Django 組件名作為項目的名稱。尤其是你應(yīng)該避免使用的命名如: django (與 Django 本身會沖突) 或者 test (與 Python 內(nèi)置的包名會沖突).
這段代碼應(yīng)該放在哪里?
如果你有一般 PHP 的編程背景(未使用流行的框架),可能會將你的代碼放在 Web 服務(wù)器的文檔根目錄下(例如:
/var/www)。而在 Django 中,你不必這么做。將任何 Python 代碼放在你的 Web 服務(wù)器文檔根目錄不會是一個好主意,因為這可能會增加人們通過 Web 方式查看到你的代碼的風(fēng)險。這不利于安全。
將你的代碼放在你的文檔根目錄 以外 的某些目錄, 例如 /home/mycode 。
讓我們來看看 startproject 都創(chuàng)建了些什么:
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
和你看到的不一樣?
默認的項目布局最近剛剛改變過。如果你看到的是一個“扁平”結(jié)構(gòu)的目錄布局(沒有內(nèi)層 mysite/ 目錄),你很可能正在使用一個和本教程版本不一致的 Django 版本。你需要切換到對應(yīng)的舊版教程或者使用較新的 Django 版本。
這些文件是:
讓我們來驗證是否工作。從外層 mysite 目錄切換進去,若準(zhǔn)備好了就運行命令 python manage.py runserver。你將會看到命令行輸出如下內(nèi)容:
Performing system checks...
0 errors found
May 13, 2015 - 15:50:53
Django version 1.8, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
你已經(jīng)啟動了 Django 開發(fā)服務(wù)器,一個純粹的由 Python 編寫的輕量級 Web 服務(wù)器。我們在 Django 內(nèi)包含了這個服務(wù)器,這樣你就可以迅速開發(fā)了,在產(chǎn)品投入使用之前不必去配置一臺生產(chǎn)環(huán)境下的服務(wù)器 – 例如 Apache 。
現(xiàn)在是一個很好的提示時機:不要 在任何類似生產(chǎn)環(huán)境中使用此服務(wù)器。它僅適用于開發(fā)環(huán)境。(我們提供的是 Web 框架的業(yè)務(wù),而不是 Web 服務(wù)器。)
現(xiàn)在服務(wù)器正在運行中,請在你的 Web 瀏覽器中訪問 http://127.0.0.1:8000/ 。 你會看到一個令人愉悅的,柔和的淡藍色 “Welcome to Django” 頁面。它工作正常!
更改端口號
默認情況下,runserver 命令啟動的開發(fā)服務(wù)器只監(jiān)聽本地 IP 的 8000 端口。
如果你想改變服務(wù)器的端口,把它作為一個命令行參數(shù)傳遞即可。例如以下命令啟動的服務(wù)器將監(jiān)聽 8080 端口:
python manage.py runserver 8080如果你想改變服務(wù)器 IP ,把它和端口號一起傳遞即可。因此,要監(jiān)聽所有公共 IP 地址(如果你想在其他電腦上炫耀你的工作),請使用:
python manage.py runserver 0.0.0.0:8000有關(guān)開發(fā)服務(wù)器的完整文檔可以在 runserver 內(nèi)參考。
現(xiàn)在,編輯 mysite/settings.py 。 這是一個普通的 Python 模塊,包含了代表 Django 設(shè)置的模塊級變量。 更改 DATABASES 中 'default' 下的以下鍵的值,以匹配您的數(shù)據(jù)庫連接設(shè)置。
當(dāng)指定路徑時,總是使用正斜杠,即使是在 Windows 下(例如:C:/homes/user/mysite/sqlite3.db) 。
如果你是新建數(shù)據(jù)庫,我們建議只使用 SQLite ,將 ENGINE 改為 'django.db.backends.sqlite3' 并且將 NAME 設(shè)置為你想存放數(shù)據(jù)庫的地方。 SQLite 是內(nèi)置在 Python 中的,因此你不需要安裝任何東西來支持你的數(shù)據(jù)庫。
Note
如果你使用 PostgreSQL 或者 MySQL,確保你已經(jīng)創(chuàng)建了一個數(shù)據(jù)庫。還是通過你的數(shù)據(jù)庫交互接口中的 “CREATE DATABASE database_name;” 命令做到這一點的。 如果你使用 SQLite ,你不需要事先創(chuàng)建任何東西 - 在需要的時候,將會自動創(chuàng)建數(shù)據(jù)庫文件。 當(dāng)你編輯 settings.py 時,將 TIME_ZONE 修改為你所在的時區(qū)。默認值是美國中央時區(qū)(芝加哥)。
同時,注意文件底部的 INSTALLED_APPS 設(shè)置。它保存了當(dāng)前 Django 實例已激活的所有 Django 應(yīng)用。每個應(yīng)用可以被多個項目使用,而且你可以打包和分發(fā)給其他人在他們的項目中使用。
默認情況下,INSTALLED_APPS 包含以下應(yīng)用,這些都是由 Django 提供的:
這些應(yīng)用在一般情況下是默認包含的。
所有這些應(yīng)用中每個應(yīng)用至少使用一個數(shù)據(jù)庫表,所以在使用它們之前我們需要創(chuàng)建數(shù)據(jù)庫中的表。要做到這一點,請運行以下命令:
python manage.py syncdb
syncdb 命令參照 INSTALLED_APPS 設(shè)置,并在你的 settings.py 文件所配置的數(shù)據(jù)庫中創(chuàng)建必要的數(shù)據(jù)庫表。每創(chuàng)建一個數(shù)據(jù)庫表你都會看到一條消息,接著你會看到一個提示詢問你是否想要在身份驗證系統(tǒng)內(nèi)創(chuàng)建個超級用戶。按提示輸入后結(jié)束。
如果你感興趣,可以在你的數(shù)據(jù)庫命令行下輸入:dt (PostgreSQL), SHOW TABLES; (MySQL), 或 .schema (SQLite) 來列出 Django 所創(chuàng)建的表。
極簡主義者
就像我們上面所說的,一般情況下以上應(yīng)用都默認包含在內(nèi),但不是每個人都需要它們。如果不需要某些或全部應(yīng)用,在運行 syncdb 命令前可從 INSTALLED_APPS 內(nèi)隨意注釋或刪除相應(yīng)的行。syncdb 命令只會為 INSTALLED_APPS 內(nèi)的應(yīng)用創(chuàng)建表。
現(xiàn)在你的項目開發(fā)環(huán)境建立好了, 你可以開工了。
你通過 Djaong 編寫的每個應(yīng)用都是由 Python 包組成的,這些包存放在你的 Python path 中并且遵循一定的命名規(guī)范。 Django 提供了個實用工具可以自動生成一個應(yīng)用的基本目錄架構(gòu),因此你可以專注于編寫代碼而不是去創(chuàng)建目錄。
項目 ( Projects ) vs. 應(yīng)用 ( apps )
項目與應(yīng)用之間有什么不同之處?應(yīng)用是一個提供功能的 Web 應(yīng)用 – 例如:一個博客系統(tǒng)、一個公共記錄的數(shù)據(jù)庫或者一個簡單的投票系統(tǒng)。 項目是針對一個特定的 Web 網(wǎng)站相關(guān)的配置和其應(yīng)用的組合。一個項目可以包含多個應(yīng)用。一個應(yīng)用可以在多個項目中使用。
你的應(yīng)用可以存放在 Python path 中的任何位置。在本教材中,我們將通過你的 manage.py 文件創(chuàng)建我們的投票應(yīng)用,以便它可以作為頂層模塊導(dǎo)入,而不是作為 mysite 的子模塊。
要創(chuàng)建你的應(yīng)用,請確認與 manage.py 文件在同一的目錄下并輸入以下命令:
python manage.py startapp polls
這將創(chuàng)建一個 polls 目錄,其展開的樣子如下所示::
polls/
__init__.py
models.py
tests.py
views.py
此目錄結(jié)構(gòu)就是投票應(yīng)用。
在 Django 中編寫一個有數(shù)據(jù)庫支持的 Web 應(yīng)用的第一步就是定義你的模型 – 從本質(zhì)上講就是數(shù)據(jù)庫設(shè)計及其附加的元數(shù)據(jù)。
哲理
模型是有關(guān)你數(shù)據(jù)的唯一且明確的數(shù)據(jù)源。它包含了你所要存儲的數(shù)據(jù)的基本字段和行為。 Django 遵循 DRY 原則 。目標(biāo)是為了只在一個地方定義你的數(shù)據(jù)模型就可從中自動獲取數(shù)據(jù)。
在這簡單的投票應(yīng)用中,我們將創(chuàng)建兩個模型: Poll 和 Choice。Poll 有問題和發(fā)布日期兩個字段。Choice 有兩個字段: 選項 ( choice ) 的文本內(nèi)容和投票數(shù)。每一個 Choice 都與一個 Poll 關(guān)聯(lián)。
這些概念都由簡單的 Python 類來表現(xiàn)。編輯 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_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
代碼很簡單。每個模型都由繼承自 django.db.models.Model 子類的類來描述。 每個模型都有一些類變量,每一個類變量都代表了一個數(shù)據(jù)庫字段。
每個字段由一個 Field 的實例來表現(xiàn) – 比如 CharField 表示字符類型的字段和 DateTimeField 表示日期時間型的字段。這會告訴 Django 每個字段都保存了什么類型的數(shù)據(jù)。
每一個 Field 實例的名字就是字段的名字(如: question 或者 pub_date ),其格式屬于親和機器式的。在你的 Python 的代碼中會使用這個值,而你的數(shù)據(jù)庫會將這個值作為表的列名。
你可以在初始化 Field 實例時使用第一個位置的可選參數(shù)來指定人類可讀的名字。這在Django的內(nèi)省部分中被使用到了,而且兼作文檔的一部分來增強代碼的可讀性。若字段未提供該參數(shù),Django 將使用符合機器習(xí)慣的名字。在本例中,我們僅定義了一個符合人類習(xí)慣的字段名 Poll.pub_date 。對于模型中的其他字段,機器名稱就已經(jīng)足夠替代人類名稱了。
一些 Field 實例是需要參數(shù)的。 例如 CharField 需要你指定 ~django.db.models.CharField.max_length。這不僅適用于數(shù)據(jù)庫結(jié)構(gòu),以后我們還會看到也用于數(shù)據(jù)驗證中。
一個 Field 實例可以有不同的可選參數(shù); 在本例中,我們將 votes 的 default 的值設(shè)為 0 。
最后,注意我們使用了 ForeignKey 定義了一個關(guān)聯(lián)。它告訴 Django 每一個Choice 關(guān)聯(lián)一個 Poll 。 Django 支持常見數(shù)據(jù)庫的所有關(guān)聯(lián):多對一( many-to-ones ),多對多( many-to-manys ) 和 一對一 ( one-to-ones )。
剛才那點模型代碼提供給 Django 大量信息。有了這些 Django 就可以做:
為該應(yīng)用創(chuàng)建對應(yīng)的數(shù)據(jù)庫架構(gòu) (CREATE TABLE statements) 。 為 Poll 和 Choice 對象創(chuàng)建 Python 訪問數(shù)據(jù)庫的 API 。 但首先,我們需要告訴我們的項目已經(jīng)安裝了 polls 應(yīng)用。
哲理
Django 應(yīng)用是“可插拔的”:你可以在多個項目使用一個應(yīng)用,你還可以分發(fā)應(yīng)用,因為它們沒有被捆綁到一個給定的 Django 安裝環(huán)境中。
再次編輯 settings.py 文件,在 INSTALLED_APPS 設(shè)置中加入 'polls' 字符。因此結(jié)果如下所示:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
# 'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'polls',
)
現(xiàn)在 Django 已經(jīng)知道包含了 polls 應(yīng)用。讓我們運行如下命令:
python manage.py sql polls
你將看到類似如下所示內(nèi)容 ( 有關(guān)投票應(yīng)用的 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") DEFERRABLE INITIALLY DEFERRED,
"choice_text" varchar(200) NOT NULL,
"votes" integer NOT NULL
);
COMMIT;
請注意如下事項:
如果你感興趣,還可以運行以下命令:
看看這些輸出的命令可以幫助你理解框架底層實際上處理了些什么。
現(xiàn)在,再次運行 syncdb 命令在你的數(shù)據(jù)庫中創(chuàng)建這些模型對應(yīng)的表:
python manage.py syncdb
syncdb 命令會給在 INSTALLED_APPS 中有但數(shù)據(jù)庫中沒有對應(yīng)表的應(yīng)用執(zhí)行 sqlall 操作。 該操作會為你上一次執(zhí)行 syncdb 命令以來在項目中添加的任何應(yīng)用創(chuàng)建對應(yīng)的表、初始化數(shù)據(jù)和創(chuàng)建索引。 syncdb 命令只要你喜歡就可以任意調(diào)用,并且它僅會創(chuàng)建不存在的表。
請閱讀 django-admin.py documentation 文檔了解 manage.py 工具更多的功能。
現(xiàn)在,我們進入 Python 的交互式 shell 中玩弄 Django 提供給你的 API 。要調(diào)用 Python sell ,使用如下命令:
python manage.py shell
我們當(dāng)前使用的環(huán)境不同于簡單的輸入 “python” 進入的 shell 環(huán)境,因為 manage.py 設(shè)置了 DJANGO_SETTINGS_MODULE 環(huán)境變量,該變量給定了 Django 需要導(dǎo)入的 settings.py 文件所在路徑。
忽略 manage.py
若你不想使用 manage.py ,也是沒有問題的。 僅需要將 DJANGO_SETTINGS_MODULE 環(huán)境變量值設(shè)為 mysite.settings 并在與 manage.py 文件所在同一目錄下運行 python ( 或確保目錄在 Python path 下,那 import mysite 就可以了 )。
想了解更多的信息,請參考 django-admin.py 文檔 。
一旦你進入了 shell,就可通過 database API 來瀏覽數(shù)據(jù)::
>>> from polls.models import Poll, Choice # Import the model classes we just wrote.
# 系統(tǒng)中還沒有 polls 。
>>> Poll.objects.all()
[]
# 創(chuàng)建一個新 Poll 。
# 在默認配置文件中時區(qū)支持配置是啟用的,
# 因此 Django 希望為 pub_date 字段獲取一個 datetime with tzinfo 。使用了 timezone.now()
# 而不是 datetime.datetime.now() 以便獲取正確的值。
>>> from django.utils import timezone
>>> p = Poll(question="What's new?", pub_date=timezone.now())
# 保存對象到數(shù)據(jù)庫中。你必須顯示調(diào)用 save() 方法。
>>> p.save()
# 現(xiàn)在對象擁有了一個ID 。請注意這可能會顯示 "1L" 而不是 "1",取決于
# 你正在使用的數(shù)據(jù)庫。 這沒什么大不了的,它只是意味著你的數(shù)據(jù)庫后端
# 喜歡返回的整型數(shù)作為 Python 的長整型對象而已。
>>> p.id
1
# 通過 Python 屬性訪問數(shù)據(jù)庫中的列。
>>> p.question
"What's new?"
>>> p.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)
# 通過改為屬性值來改變值,然后調(diào)用 save() 方法。
>>> p.question = "What's up?"
>>> p.save()
# objects.all() 用以顯示數(shù)據(jù)庫中所有的 polls 。
>>> Poll.objects.all()
[<Poll: Poll object>]
請稍等。<Poll: Poll object> 這樣顯示對象絕對是無意義的。 讓我們編輯 polls 模型( 在 polls/models.py 文件中 ) 并且給 Poll 和 Choice 都添加一個 unicode() 方法來修正此錯誤:
class Poll(models.Model):
# ...
def __unicode__(self):
return self.question
class Choice(models.Model):
# ...
def __unicode__(self):
return self.choice_text
給你的模型添加 unicode() 方法是很重要的, 不僅是讓你在命令行下有明確提示,而且在 Django 自動生成的管理界面中也會使用到對象的呈現(xiàn)。
為什么是 unicode() 而不是 str()?
如果你熟悉 Python,那么你可能會習(xí)慣在類中添加 str() 方法而不是 unicode() 方法。 We use 我們在這里使用 unicode() 是因為 Django 模型默認處理的是 Unicode 格式。當(dāng)所有存儲在數(shù)據(jù)庫中的數(shù)據(jù)返回時都會轉(zhuǎn)換為 Unicode 的格式。
Django 模型有個默認的 str() 方法 會去調(diào)用 unicode() 并將結(jié)果轉(zhuǎn)換為 UTF-8 編碼的字符串。這就意味著 unicode(p) 會返回一個 Unicode 字符串,而 str(p) 會返回一個以 UTF-8 編碼的普通字符串。
如果這讓你感覺困惑,那么你只要記住在模型中添加 unicode() 方法。 運氣好的話,這些代碼會正常運行。
請注意這些都是普通的 Python 方法。讓我們來添加個自定義方法,為了演示而已:
import datetime
from django.utils import timezone
# ...
class Poll(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
請注意,增加了 import datetime 和 from django.utils import timezone, 是為了分別引用 Python 的標(biāo)準(zhǔn)庫 datetime 模塊和 Django 的 django.utils.timezone 中的 time-zone-related 實用工具 。如果你不熟悉在 Python 中處理時區(qū),你可以在 時區(qū)支持文檔 學(xué)到更多。
保存這些更改并且再次運行 python manage.py shell 以開啟一個新的 Python shell:
>>> from polls.models import Poll, Choice
# 確認我們附加的 __unicode__() 正常運行。
>>> Poll.objects.all()
[<Poll: What's up?>]
# Django 提供了一個豐富的數(shù)據(jù)庫查詢 API ,
# 完全由關(guān)鍵字參數(shù)來驅(qū)動。
>>> Poll.objects.filter(id=1)
[<Poll: What's up?>]
>>> Poll.objects.filter(question__startswith='What')
[<Poll: What's up?>]
# 獲取今年發(fā)起的投票。
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Poll.objects.get(pub_date__year=current_year)
<Poll: What's up?>
# 請求一個不存在的 ID ,這將引發(fā)一個異常。
>>> Poll.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Poll matching query does not exist. Lookup parameters were {'id': 2}
# 根據(jù)主鍵查詢是常見的情況,因此 Django 提供了一個
# 主鍵精確查找的快捷方式。
# 以下代碼等同于 Poll.objects.get(id=1).
>>> Poll.objects.get(pk=1)
<Poll: What's up?>
# 確認我們自定義方法正常運行。
>>> p = Poll.objects.get(pk=1)
>>> p.was_published_recently()
True
# 給 Poll 設(shè)置一些 Choices 。通過 create 方法調(diào)用構(gòu)造方法去創(chuàng)建一個新
# Choice 對象實例,執(zhí)行 INSERT 語句后添加該 choice 到
# 可用的 choices 集中并返回這個新建的 Choice 對象實例。 Django 創(chuàng)建了
# 一個保存外鍵關(guān)聯(lián)關(guān)系的集合 ( 例如 poll 的 choices) 以便可以通過 API
# 去訪問。
>>> p = Poll.objects.get(pk=1)
# 從關(guān)聯(lián)對象集中顯示所有 choices -- 到目前為止還沒有。
>>> p.choice_set.all()
[]
# 創(chuàng)建三個 choices 。
>>> p.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> p.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = p.choice_set.create(choice_text='Just hacking again', votes=0)
# Choice 對象擁有訪問它們關(guān)聯(lián)的 Poll 對象的 API 。
>>> 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 會自動連續(xù)關(guān)聯(lián)。
# 使用雙下劃線來隔離關(guān)聯(lián)。
# 只要你想要幾層關(guān)聯(lián)就可以有幾層關(guān)聯(lián),沒有限制。
# 尋找和今年發(fā)起的任何 poll 有關(guān)的所有 Choices
# ( 重用我們在上面建立的 'current_year' 變量 )。
>>> Choice.objects.filter(poll__pub_date__year=current_year)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
# 讓我們使用 delete() 刪除 choices 中的一個。
>>> c = p.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
欲了解更多有關(guān)模型關(guān)系的信息,請查看 訪問關(guān)聯(lián)對象 。欲了解更多有關(guān)如何使用雙下劃線來通過 API 執(zhí)行字段查詢的,請查看 字段查詢 。 如需完整的數(shù)據(jù)庫 API 信息,請查看我們的 數(shù)據(jù)庫 API 參考 。
當(dāng)你對 API 有所了解后, 請查看 教程 第2部分 來學(xué)習(xí) Django 的自動生成的管理網(wǎng)站是如何工作的。
譯者:Django 文檔協(xié)作翻譯小組,原文:Part 1: Models。
本文以 CC BY-NC-SA 3.0 協(xié)議發(fā)布,轉(zhuǎn)載請保留作者署名和文章出處。
Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群:467338606。