對Django這個 架構 感 興趣 好久了,卻一直懶于 研究 學習 ,現在跟随官網的 教程 跑一遍,學學Django同時也 繼續 學學 Python 。
在開始之前, 我們 先把Python和Django這個架構安裝好。
官網: https://www.djangoproject.com/
下載下傳 :http://www.djangoproject. com /download/1.3/tarball/
由于相容性 問題 ,Django并不支援Python3+,隻支援版本2.4到2.7,是以如果你的 系統 (本人使用的是SUSE Linux Enterprise Server 10 SP3,以下都是以這個系統為例)沒有安裝Python,或者版本不 符合 ,那麼就先要安裝一個合适的版本,我使用的是2.7.2版本:
1 | wget http://www.python.org/ ftp /python/2.7.2/Python-2.7.2. tar .bz2 |
2 | tar jxvf Python-2.7.2. tar .bz2 |
下載下傳完後運作python setup.py install進行安裝:
1 | wget http://media.djangoproject.com/releases/1.3/Django-1.3. tar .gz |
2 | tar xzvf Django-1.3. tar .gz |
4 | python setup.py install |
安裝完成後, 驗證 下是否 成功 , 輸入 python進入指令行,然後輸入如下語句導入django并且輸出django的版本号:
2 | >>> print django.get_version() |
OK,下面我們 可以 正式開始了。 在這個教程裡,我們會建立一個簡單的投票 應用 。它包括兩部分:
- 一個公共網頁讓人檢視投票和進行投票。
- 一個管理網頁讓你添加,修改和删除投票
擷取幫助:
如果你對這個教程有任何疑問,請到django-users留言或者在irc.freenode.net上通路#django,找一些可能為你提供幫助的Django使用者。
建立項目
下面開始 建立 一個項目。首先 cd 到存放項目的目錄,然後運作 django-admin.py startproject mysite 指令建立項目:
2 | 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并且去到django-admin.py被安裝到的目錄,并運作指令chmod +x django-admin.py來解決這個問題。
注意
要避免跟Python和Django元件的命名沖突,避免使用像django和test這樣的命名。
如果你是通過 python setup.py 安裝Django的話,django-admin.py應該會在你的系統 路徑 下。如果它不在這個路徑上的話,你可以在 site-packages/django/bin 裡找到它, site-packages 是你安裝Python的目錄。你可以考慮把某個路徑軟 連結 到django-admin.py,例如 /usr/local/bin 。
代碼應該放在哪
如果你是PHP出身的話,你大概會把代碼放在Web Server的根目錄下(例如/var/www)。但在Django裡,别這麼幹。把Python代碼放在Web Server的根目錄裡并不是一個好主意,因為有被人在網頁上看到代碼的風險。這個不利于安全。
把你的代碼放在根目錄外面的地方,例如/home/mycod(我這裡用的目錄是/home/python)。
回到正題,startproject建立的目錄結構如下:
這些檔案的用途是:
- __init__.py: 一個空檔案讓Python知道這個目錄是一個Python包。(如果你是一個Python初學者,可以看官方的Python文檔了解更多關于包的内容)
- manage.py: 一個指令行工具用于跟項目的各種互動。詳情檢視django-admin.py和manage.py這兩個檔案。
- settings.py: 目前項目的設定和配置。詳情可以檢視Django settings。
- urls.py: 目前項目的URL定義。詳情可以檢視URL dispatcher。
開發用伺服器
下面啟動Django development server來檢查下成果。進入項目目錄 mysite 運作指令 python manage.py runserver :
Django version 1.3, using settings 'mysite.settings' |
Development server is running at http://127.0.0.1:8000/ |
Quit the server with CONTROL-C. |
你已經啟動了Django的開發 服務 器,一個用純Python編寫的輕量級Web server。我們已經把它包含在Django裡,這樣你就可以進行快速的開發而不需要去配置諸如 apache 這樣的Production伺服器,除非你已經準備好要釋出了。
注意不要把這個伺服器當作釋出環境用,它是專門在開發環境中使用的。
現在服務已經啟動了,你可以在 浏覽器 上通路http://127.0.0.1:8000/。你将會看到歡迎 頁面 ,如下圖:
改變端口
runserver指令的預設端口是8000。
如果你想改變端口,你可以把它作為參數傳給指令行,例如,這個指令會在端口8080上啟動服務:
python manage.py runserver 8080 |
如果想改變IP,那麼可以跟端口一起傳給指令行。如果要監聽所有的公共IP,可以這樣:
python manage.py runserver 0.0.0.0:8000 |
開發伺服器的文檔可以在runserver裡找到。
資料庫配置
現在, 編輯 settings.py 檔案。修改DATABASES的 default 項裡下面的值:
- ENGINE:django.db.backends.postgresql_psycopg2或者django.db.backends.mysql和django.db.backends.sqlite3。也支援其他資料庫。
- NAME:資料庫名。如果使用的是SQLite的話,資料庫則是系統裡的一個檔案,是以NAME應該設為包含這個檔案名字的絕對路徑(注意路徑要使用斜杠/,無論在什麼系統上)。這個檔案不需要建立,在第一次進行資料庫同步的時候會自動建立這個檔案。
- USER:使用者名。使用SQLite的話則不需要。
- PASSWORD:密碼。使用SQLite的話則不需要。
- HOST:主機位址。使用SQLite的話則不需要。如果資料庫安裝在同一台機器上,也可以不指定。
如果你對資料庫不太熟悉的話, 建議 你使用SQLite(把 ENGINE 設為 django.db.backends.sqlite3 )。SQLite已經作為Python 2.5以上版本的一部分包含在裡面,是以你不需要作任何的安裝。
在編輯 settings.py 的時候,你會注意到檔案底部的INSTAL LED _APPS配置項。這些變量儲存了那些随着Django執行個體啟動的Django應用(以下用app表示)的名字。app可以被使用到多個項目裡,你也可以把它們打包和釋出出去供其他人使用。 INSTALLED_APPS預設包含了以下app,這些app全部由Django自帶:
- django.contrib.auth -- 一個認證系統。
- django.contrib.contenttypes -- 内容類型架構。
- django.contrib.sessions -- session架構。
- django.contrib.sites -- 多網站管理架構。
- django.contrib.messages -- 消息管理架構。
- django.contrib.staticfiles -- 靜态檔案管理架構。
為了友善使用,這些通常 網站 都會用到的應用已經預設包含在項目裡。 這些app每個都至少要用到一個以上的資料庫表,是以在使用這些應用前我們先要建立這些表。運作一下指令:
syncdb指令會根據 settings.py 檔案裡的INSTALLED_APPS設定建立必需的資料表。你會看到建立表的資訊以及會提示你為認證系統建立超級使用者,跟着提示做就行了。
簡化
就像我們上面說的,基于常理,預設的那些應用會被自動包含,但是并不是所有人都會用到它們。是以如果你不需要用到這些應用,你可以在執行syncdb指令前随意把它們在INSTALLED_APPS裡注釋掉或者删掉。syncdb隻會為INSTALLED_APPS裡的應用建立表。
建立模型
現在環境已經搭好了,可以正式開工了。
在Django裡,你寫的每個應用都包含一個Python的包,這個包會根據一個特定的約定放在Python path裡。Django會自動為每個app建立一些 基本 的目錄結構,是以你可以專心寫代碼而不必在建立目錄上費心。
Projects vs. apps
項目跟app有什麼不同呢?app是一個實作某個功能的網頁應用,例如一個網頁日志系統,一個公共資料資料庫或者一個簡單的投票應用。而一個項目則是由一堆配置和應用組成的網頁。一個項目可以包含多個應用,而一個應用可以使用在多個項目裡。
你的應用可以存放在Python path上的任何地方。簡單起見,我們在 mysite 目錄裡建立一個投票應用。确認你的目前目錄為 mysite ,并輸入指令:
python manage.py startapp polls |
這樣會建立一個目錄polls,如下:
這個目錄結構将會存放這個poll應用。
在Django裡寫一個有資料庫操作的網頁應用第一步要做的就是定義模型(Model),模型實質上就是附帶中繼資料的資料層(database layout)。
原理(Philosophy)
模型是跟你的資料相關的一個單一和明确的資料源。它包含了你所儲存的資料的一些必要字段和行為。Django遵循DRY原則,目的是在一個地方定義你的資料模型然後根據它自動派生出其他的東西。
在我們這個簡單的投票應用裡,我們建立了兩個模型:polls和choices。一個poll包含有一個問題和一個發表日期。一個choice有兩個字段:選項 文字 和投票計數。每一個choice都跟一個poll關聯。
這個概念将由一個簡單的Python類來實作。編輯檔案 polls/models.py :
1 | from django.db import models |
2 | class Poll(models.Model): |
3 | question = models.CharField(max_length = 200 ) |
4 | pub_date = models.DateTimeField( 'date published' ) |
5 | class Choice(models.Model): |
6 | poll = models.ForeignKey(Poll) |
7 | choice = models.CharField(max_length = 200 ) |
8 | votes = models.IntegerField() |
代碼很直白。每個模型都由一個django.db.models.Model的子類實作。每個模型包含一些變量,每個變量對應一個資料庫裡的字段。
每個字段由類Field的一個執行個體表示,例如字元類型的字段由CharField實作, 時間 類型的字段則由DateTimeField實作,這樣Django就知道每個字段儲存的是什麼類型的資料了。
每個Field執行個體的名字(例如 question 和 pub_date )都是機器友好格式的字段名。這些字段會用在你的Python代碼裡,而資料庫則會把它用作字段名。
你可以在Field的第一個參數指定一個可讀的名字,這個名字會用在Django内部多個地方。如果沒有指定這個名字,Django會使用機器可讀的名字。在這個例子裡,我們隻為 Poll.pub_date 定義了人可讀的名字,模型裡其他所有的字段,機器可讀名字已經可作為人可讀名字。
一些Field類有必須含有的元素,例如CharField,必須給它指定 max_length 。這個不僅會用在資料庫schema裡,也會用在資料驗證裡,我們很快會看到。
最後,注意到用ForeignKey定義了一個 關系 。它告訴Django每個Choice會關聯到一個Poll。Django支援所有的 常用 資料庫關系:多對已,多對多和一對一。
激活模型
Django通過模型裡的那點代碼擷取到了很多的資訊,通過這些資訊,Django可以:
- 為應用建立資料庫模式(CREATE TABLE語句) 。
- 建立通路Poll和Choice對象的Python資料庫通路API。
但是首先我們先要讓我們的項目知道 polls 這個應用已經安裝。
原理(Philosophy)
Django應用是“可插拔式”的:你可以把一個應用用在多個項目裡,也可以把它釋出出去,因為它們不是跟Django的安裝綁定的。
再次編輯檔案 settings.py ,修改設定INSTALLED_APPS包含字元串 'polls' 。修改後的配置如下:
'django.contrib.contenttypes', |
'django.contrib.sessions', |
現在Django知道要去包含 polls 這個應用了。我們執行 另外 一個指令:
python manage.py sql polls |
你應該會看到類似下面的東西(poll應用的 CREATE TABLE SQL語句):
CREATE TABLE "polls_poll" ( |
"id" integer NOT NULL PRIMARY KEY, |
"question" varchar(200) NOT NULL, |
"pub_date" datetime NOT NULL |
CREATE TABLE "polls_choice" ( |
"id" integer NOT NULL PRIMARY KEY, |
"poll_id" integer NOT NULL REFERENCES "polls_poll" ( "id" ), |
"choice" varchar(200) NOT NULL, |
注意以下幾點:
- 實際輸出的東西會根據你所使用的資料庫而不同。
- 表名由應用的名稱(polls)和小寫的模型名稱 —— poll和choice組合而成并自動生成。(你可以重寫這個規則。)
- 主鍵(IDs)會被自動添加。(同樣能可以重寫它)
- 為了友善,Django會添加"_id"到外鍵的字段名上。對的,你同樣可以重寫它。
- 外鍵關系由一個REFERENCES語句明确确定。
- 它是為你所使用的資料庫量身定制的,是以資料庫特有的字段如auto_increment (MySQL),serial (PostgreSQL)或者integer primary key (SQLite)都會自動幫你處理,同樣字段名的引号也是如此,例如,是使用雙引号還是單引号。這篇教程的作者使用PostgreSQL,是以例子裡的輸出都是PostgreSQL文法。
- sql指令并不會在你的資料庫裡執行SQL語句,它隻是在螢幕上顯示給你看Django認為需要執行哪些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和sqlindexes指令産生的SQL語句的結合。
看這些指令的輸出可以幫助你更好的 了解 底層發生的事情。
現在,再次運作syncdb在資料庫上建立這些模型的表:
syncdb指令會為在INSTALLED_APPS裡沒有相應資料表的應用運作'sqlall'産生的sql語句。它會為自上次運作syncdb以來新添加的應用建立所有的表,初始化資料和 索引 。你可以在任何時候執行syncdb,它隻會建立不存在的表。
閱讀django-admin.py documentation以擷取 manage.py 這個工具所能做的事情的所有資訊。
使用API
現在,我們進入Python的互動 shell 并使用Django提供的API。要進入Python shell,使用這個指令:
我在這裡遇到了ImportError: No module named readline這個錯誤, 解決方法 是下載下傳readline,編譯安裝,然後重新編譯和安裝python就可以解決這個問題。
我們使用這個而不是簡單的輸入"python",是因為 manage.py 會幫你建立項目的環境。“建立項目環境”包括兩件事:
省略manage.py
如果你不想使用manage.py,沒問題,隻需要確定mysite和polls 位于Python路徑的根目錄 (例如import mysite和import polls能正常工作)以及把DJANGO_SETTINGS_MODULE這個環境變量設定到mysite.settings裡。
更多的資訊可以檢視django-admin.py documentation.
在shell裡面時,可以 探索 下database API:
>>> from polls.models import Poll, Choice # 導入我們剛寫的模型。 |
>>> p = Poll(question = "What's up?" , pub_date = datetime.datetime.now()) |
# 把對象儲存進資料庫裡。你需要明确調用save()。 |
# 現在它有個ID了。注意這裡也可能顯示1L而不是1, |
# 取決于你使用的是什麼資料庫。不過這沒什麼打不了, |
# 它隻是表明資料庫更傾向于把整型傳回成Python的長整型對象。 |
datetime.datetime( 2007 , 7 , 15 , 12 , 00 , 53 ) |
>>> p.pub_date = datetime.datetime( 2007 , 4 , 1 , , ) |
# objects.all()顯示資料庫所有的poll。 |
等等。 <Poll: Poll object> 完全不能表現出這個對象的 有用資訊 。我們可以編輯poll模型(在檔案 polls/models.py 裡)添加一個__unicode__() 方法 給 Poll 和 Choice 來解決這個問題:
class Poll(models.Model): |
class Choice(models.Model): |
為你的模型添加__unicode__()方法是很有必要的。不僅是為了讓你自己更好了解互動提示,而且因為對象的表現的使用會貫穿于整個Django自動産生的admin。
為什麼是__unicode__()而不是__str__()?
如果你熟悉Python的話,你可能會更喜歡在你的類裡添加__str__()而不是__unicode__()方法。我們這裡使用__unicode__()是因為Django模型預設使用Unicode,所有儲存在資料庫的資料在傳回的時候都會轉化成Unicode。
Django模型有一個預設的__str__()方法叫__unicode__(),它會把結果集轉化成UTF-8位元組字元串。在各個意味着unicode(p)會傳回一個Unicode字元串,而str(p)會傳回一個普通的UTF-8編碼的字元串。
如果你還是覺得莫名其妙的話,記得把__unicode__()方法加進你的模型中就行了,幸運的話,一切都會如你所想工作。
注意這些都是普通的Python方法,讓我們添加一個自定義的方法,用作示範:
class Poll(models.Model): |
def was_published_today( self ): |
return self .pub_date.date() = = datetime.date.today() |
添加 import datetime 會引用Python的 datetime 子產品。 儲存這些修改然後再次運作 python manage.py shell 新開一個Python互動shell:
>>> from polls.models import Poll, Choice |
# 確定我們新加的__unicode__()正常工作。 |
>>> Poll.objects. filter ( id = 1 ) |
>>> Poll.objects. filter (question__startswith = 'What' ) |
>>> Poll.objects.get(pub_date__year = 2007 ) |
>>> 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 ) |
>>> p = Poll.objects.get(pk = 1 ) |
>>> p.was_published_today() |
# 調用建立函數建立choice對象,會調用INSERT語句, |
# 把choice添加到已存choice的集合裡,并傳回這個新建立的Choice對象。 |
# Django會建立一個集合儲存外鍵關聯,這個集合可以通過API進行通路。 |
>>> p = Poll.objects.get(pk = 1 ) |
# 顯示關聯的所有choice —— 目前還沒有。 |
>>> p.choice_set.create(choice = 'Not much' , votes = ) |
>>> p.choice_set.create(choice = 'The sky' , votes = ) |
>>> c = p.choice_set.create(choice = 'Just hacking again' , votes = ) |
# Choice對象可通過API通路它關聯的Poll對象。 |
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] |
# 查找pub_date在2007年的poll的所有choice。 |
>>> Choice.objects. filter (poll__pub_date__year = 2007 ) |
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] |
# 我們使用delete()删除一個choice。 |
>>> c = p.choice_set. filter (choice__startswith = 'Just hacking' ) |
更多關于模型關系的資訊,可以看Accessing related objects。想知道更多關于如何使用雙下劃線通過API實作字段的查找,看Field lookups。要擷取資料庫API的所有資訊,請看Database API reference。
好吧,開篇就到這裡,更詳細請檢視:
https://docs.djangoproject.com/en/dev/intro/tutorial01/
Written by icyfire @ 2011.08.05 updated @ 2011.10.09