或者http://docs.30c.org/djangobook2/chapter01/html
django-admin.py startproject mysite命令建立一個目錄,包含4個文件:python
mysite/ __init__.py manage.py settings.py urls.py
文件以下:mysql
__init__.py :讓 Python 把該目錄當成一個開發包 (即一組模塊)所需的文件。 這是一個空文件,通常你不須要修改它。web
manage.py :一種命令行工具,容許你以多種方式與該 Django 項目進行交互。 鍵入python manage.py help,看一下它能作什麼。 你應當不須要編輯這個文件;在這個目錄下生成它純是爲了方便。正則表達式
settings.py :該 Django 項目的設置或配置。 查看並理解這個文件中可用的設置類型及其默認值。sql
默認狀況下, runserver 命令在 8000 端口啓動開發服務器,且僅監聽本地鏈接。 要想要更改服務器端口的話,可將端口做爲命令行參數傳入:shell
python manage.py runserver 8080
經過指定一個 IP 地址,你能夠告訴服務器–容許非本地鏈接訪問。 若是你想和其餘開發人員共享同一開發站點的話,該功能特別有用。 `` 0.0.0.0`` 這個 IP 地址,告訴服務器去偵放任意的網絡接口。數據庫
python manage.py runserver 0.0.0.0:8000
Hello world視圖很是簡單。 這些是完整的函數和導入聲明,你須要輸入到views.py文件:django
from django.http import HttpResponse def hello(request): return HttpResponse("Hello world")
咱們逐行逐句地分析一遍這段代碼:編程
首先,咱們從 django.http 模塊導入(import) HttpResponse 類。參閱附錄 H 瞭解更多關於 HttpRequest 和 HttpResponse 的細節。 咱們須要導入這些類,由於咱們會在後面用到。
接下來,咱們定義一個叫作hello 的視圖函數。
每一個視圖函數至少要有一個參數,一般被叫做request。 這是一個觸發這個視圖、包含當前Web請求信息的對象,是類django.http.HttpRequest的一個實例。在這個示例中,咱們雖然不用request作任何事情,然而它仍必須是這個視圖的第一個參數。
這個函數只有簡單的一行代碼: 它僅僅返回一個HttpResponse對象,這個對象包含了文本「Hello world」。
默認的URLconf包含了一些被註釋起來的Django中經常使用的功能,僅僅只需去掉這些註釋就能夠開啓這些功能. 下面是URLconf中忽略被註釋的行後的實際內容
from django.conf.urls.defaults import * urlpatterns = patterns('', )
讓咱們逐行解釋一下代碼:
第一行導入django.conf.urls.defaults下的全部模塊,它們是Django URLconf的基本構造。 這包含了一個patterns函數。
若是想在URLconf中加入URL和view,只需增長映射URL模式和view功能的Python tuple便可. 這裏演示如何添加view中hello功能.
from django.conf.urls.defaults import *#其實只用到了裏面的pattern
from mysite.views import hello#這句報錯,我修改爲去掉了mysite.
urlpatterns = patterns('', ('^hello/$', hello), )#正則表達式
請留意:爲了簡潔,咱們移除了註釋代碼。 若是你喜歡的話,你能夠保留那些行。)
咱們作了兩處修改。
首先,咱們從模塊 (在 Python 的 import 語法中, mysite/views.py 轉譯爲 mysite.views ) 中引入了 hello 視圖。 (這假設mysite/views.py在你的Python搜索路徑上。關於搜索路徑的解釋,請參照下文。)
接下來,咱們爲urlpatterns加上一行: (‘^hello/$’, hello), 這行被稱做URLpattern,它是一個Python的元組。元組中第一個元素是模式匹配字符串(正則表達式);第二個元素是那個模式將使用的視圖函數。
正則表達式
正則表達式 (或 regexes ) 是通用的文本模式匹配的方法。 Django URLconfs 容許你 使用任意的正則表達式來作強有力的URL映射,不過一般你實際上可能只須要使用不多的一 部分功能。 這裏是一些基本的語法。
符號 | 匹配 |
---|---|
. (dot) | 任意單一字符 |
\d | 任意一位數字 |
[A-Z] | A 到 Z中任意一個字符(大寫) |
[a-z] | a 到 z中任意一個字符(小寫) |
[A-Za-z] | a 到 z中任意一個字符(不區分大小寫) |
+ | 匹配一個或更多 (例如, \d+ 匹配一個或 多個數字字符) |
[^/]+ | 一個或多個不爲‘/’的字符 |
? | 零個或一個以前的表達式(例如:\d? 匹配零個或一個數字) |
* | 匹配0個或更多 (例如, \d* 匹配0個 或更多數字字符) |
{1,3} | 介於一個和三個(包含)以前的表達式(例如,\d{1,3}匹配一個或兩個或三個數字) |
這些敏感信息若是部署到了因特網上的站點就不該該暴露 這些信息。這個「Page not found」頁面只會在 調試模式(debug mode) 下 顯示。 咱們將在之後說明怎麼關閉調試模式。
全部均開始於setting文件。當你運行python manage.py runserver,腳本將在於manage.py同一個目錄下查找名爲setting.py的文件。這個文件包含了全部有關這個Django項目的配置信息,均大寫: TEMPLATE_DIRS , DATABASE_NAME , 等. 最重要的設置時ROOT_URLCONF,它將做爲URLconf告訴Django在這個站點中那些Python的模塊將被用到
還記得何時django-admin.py startproject建立文件settings.py和urls.py嗎?自動建立的settings.py包含一個ROOT_URLCONF配置用來指向自動產生的urls.py. 打開文件settings.py你將看到以下:
ROOT_URLCONF = 'mysite.urls'
相對應的文件是mysite/urls.py
當訪問 URL /hello/ 時,Django 根據 ROOT_URLCONF 的設置裝載 URLconf 。 而後按順序逐個匹配URLconf裏的URLpatterns,直到找到一個匹配的。 當找到這個匹配 的URLpatterns就調用相關聯的view函數,並把 HttpRequest 對象做爲第一個參數。
總結一下:
進來的請求轉入/hello/.
Django經過在ROOT_URLCONF配置來決定根URLconf.
Django在URLconf中的全部URL模式中,查找第一個匹配/hello/的條目。
若是找到匹配,將調用相應的視圖函數
視圖函數返回一個HttpResponse
Django轉換HttpResponse爲一個適合的HTTP response, 以Web page顯示出來
from django.conf.urls.defaults import * from mysite.views import hello, current_datetime urlpatterns = patterns('', ('^hello/$', hello), ('^time/$', current_datetime), )
寫好視圖而且更新URLconf以後,運行命令python manage.py runserver以啓動服務,在瀏覽器中輸入http://127.0.0.1:8000/time/。 你將看到當前的日期和時間。
若是咱們想要輸出這個函數到 一些 URL, 咱們只須要修改URL配置而不用 去改動視圖的代碼。
如何設計程序來處理任意數量的時差? 答案是:使用通配符(wildcard URLpatterns)。正如咱們以前提到過,一個URL模式就是一個正則表達式。所以,這裏可使用d+來匹配1個以上的數字。
urlpatterns = patterns('',
# ...
(r'^time/plus/\d+/$', hours_ahead),
# ...
)
這裏使用# …來表示省略了其它可能存在的URL模式定義。 (見上)
這個URL模式將匹配相似 /time/plus/2/ , /time/plus/25/ ,甚至 /time/plus/100000000000/ 的任何URL。 更進一步,讓咱們把它限制在最大容許99個小時, 這樣咱們就只容許一個或兩個數字,正則表達式的語法就是 \d{1,2} :
(r'^time/plus/\d{1,2}/$', hours_ahead),
備註
在建造Web應用的時候,儘量多考慮可能的數據輸入是很重要的,而後決定哪些咱們能夠接受。 在這裏咱們就設置了99個小時的時間段限制。
另一個重點,正則表達式字符串的開頭字母「r」。 它告訴Python這是個原始字符串,不須要處理裏面的反斜槓(轉義字符)。 在普通Python字符串中,反斜槓用於特殊字符的轉義。好比n轉義成一個換行符。 當你用r把它標示爲一個原始字符串後,Python再也不視其中的反斜槓爲轉義字符。也就是說,「n」是兩個字符串:「」和「n」。因爲反斜槓在Python代碼和正則表達式中有衝突,所以建議你在Python定義正則表達式時都使用原始字符串。 從如今開始,本文全部URL模式都用原始字符串。
hours_ahead 和咱們之前寫的 current_datetime 很象,關鍵的區別在於: 它多了一個額外參數,時間差。如下是view代碼:
from django.http import Http404, HttpResponse import datetime def hours_ahead(request, offset): try: offset = int(offset)
except ValueError: raise Http404()
dt = datetime.datetime.now() + datetime.timedelta(hours=offset) html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt) return HttpResponse(html)
讓咱們逐行分析一下代碼:
視圖函數, hours_ahead , 有 兩個 參數: request 和 offset . (見上)
request 是一個 HttpRequest 對象, 就像在 current_datetime 中同樣. 再說一次好了: 每個視圖 老是 以一個 HttpRequest 對象做爲 它的第一個參數。 (見上)
offset 是從匹配的URL裏提取出來的。 例如:若是請求URL是/time/plus/3/,那麼offset將會是3;若是請求URL是/time/plus/21/,那麼offset將會是21。請注意:捕獲值永遠都是字符串(string)類型,而不會是整數(integer)類型,即便這個字符串全由數字構成(如:「21」)。
(從技術上來講,捕獲值老是Unicode objects,而不是簡單的Python字節串,但目前不須要擔憂這些差異。)
在這裏咱們命名變量爲 offset ,你也能夠任意命名它,只要符合Python 的語法。 變量名是可有可無的,重要的是它的位置,它是這個函數的第二個 參數 (在 request 的後面)。 你還可使用關鍵字來定義它,而不是用 位置。
咱們在這個函數中要作的第一件事情就是在 offset 上調用 int() . 這會把這個字符串值轉換爲整數。
請留意:若是你在一個不能轉換成整數類型的值上調用int(),Python將拋出一個ValueError異常。如:int(‘foo’)。在這個例子中,若是咱們遇到ValueError異常,咱們將轉爲拋出django.http.Http404異常——正如你想象的那樣:最終顯示404頁面(提示信息:頁面不存在)。
<ul> {% for item in item_list %} <li>{{ item }}</li> {% endfor %} </ul> {% if ordered_warranty %} <p>Your warranty information will be included in the packaging.</p> {% else %} <p>You didn't order a warranty, so you're on your own when the products inevitably stop working.</p> {% endif %}
用兩個大括號括起來的文字(例如 {{ person_name }} )稱爲 變量(variable) 。這意味着將按照給定的名字插入變量的值。 如何指定變量的值呢? 稍後就會說明。
被大括號和百分號包圍的文本(例如 {% if ordered_warranty %} )是 模板標籤(template tag) 。標籤(tag)定義比較明確,即: 僅通知模板系統完成某些工做的標籤。
這個例子中的模板包含一個for標籤( {% for item in item_list %} )和一個if 標籤({% if ordered_warranty %} )
for標籤相似Python的for語句,可以讓你循環訪問序列裏的每個項目。 if 標籤,正如你所料,是用來執行邏輯判斷的。 在這裏,tag標籤檢查ordered_warranty值是否爲True。若是是,模板系統將顯示{% if ordered_warranty %}和{% else %}之間的內容;不然將顯示{% else %}和{% endif %}之間的內容。{% else %}是可選的。
最後,這個模板的第二段中有一個關於filter過濾器的例子,它是一種最便捷的轉換變量輸出格式的方式。 如這個例子中的{{ship_date|date:」F j, Y」 }},咱們將變量ship_date傳遞給date過濾器,同時指定參數」F j,Y」。date過濾器根據參數進行格式輸出。 過濾器是用管道符(|)來調用的,具體能夠參見Unix管道符。
Django 模板含有不少內置的tags和filters,咱們將陸續進行學習. 附錄F列出了不少的tags和filters的列表,
在Python代碼中使用Django模板的最基本方式以下:
能夠用原始的模板代碼字符串建立一個 Template 對象, Django一樣支持用指定模板文件路徑的方式來建立 Template 對象;
調用模板對象的render方法,而且傳入一套變量context。它將返回一個基於模板的展示字符串,模板中的變量和標籤會被context值替換。
代碼以下:
>>> from django import template >>> t = template.Template('My name is {{ name }}.') >>> c = template.Context({'name': 'Adrian'}) >>> print t.render(c) My name is Adrian. >>> c = template.Context({'name': 'Fred'}) >>> print t.render(c) My name is Fred.
建立一個 Template 對象最簡單的方法就是直接實例化它。 Template 類就在 django.template 模塊中,構造函數接受一個參數,原始模板代碼。 讓咱們深刻挖掘一下 Python的解釋器看看它是怎麼工做的。
轉到project目錄(在第二章由 django-admin.py startproject 命令建立), 輸入命令 python manage.py shell 啓動交互界面。
一個特殊的Python提示符
若是你曾經使用過Python,你必定好奇,爲何咱們運行python manage.py shell而不是python。這兩個命令都會啓動交互解釋器,可是manage.py shell命令有一個重要的不一樣: 在啓動解釋器以前,它告訴Django使用哪一個設置文件。 Django框架的大部分子系統,包括模板系統,都依賴於配置文件;若是Django不知道使用哪一個配置文件,這些系統將不能工做。
瞭解一些模板系統的基本知識:
>>> from django.template import Template >>> t = Template('My name is {{ name }}.') >>> print t
若是你跟咱們一塊兒作,你將會看到下面的內容:
<django.template.Template object at 0xb7d5f24c>
0xb7d5f24c 每次都會不同,這沒什麼關係;這只是Python運行時 Template 對象的ID。
當你建立一個 Template 對象,模板系統在內部編譯這個模板到內部格式,並作優化,作好 渲染的準備。 若是你的模板語法有錯誤,那麼在調用 Template() 時就會拋出 TemplateSyntaxError 異常:
>>> from django.template import Template >>> t = Template('{% notatag %}') Traceback (most recent call last): File "<stdin>", line 1, in ? ... django.template.TemplateSyntaxError: Invalid block tag: 'notatag'
這裏,塊標籤(block tag)指向的是`` {% notatag %}``,塊標籤與模板標籤是同義的。
字典和Contexts
Python的字典數據類型就是關鍵字和它們值的一個映射。 Context 和字典很相似, Context 還提供更多的功能,請看第九章。
t = Template('Hello, {{ name }}')
for name in ('John', 'Julie', 'Pat'):
print t.render(Context({'name': name}))
-------------
模板系統可以很是簡潔地處理更加複雜的數據結構,例如list、dictionary和自定義的對象。
在 Django 模板中遍歷複雜數據結構的關鍵是句點字符 (.)。
點語法也能夠用來引用對象的* 方法*。
句點也可用於訪問列表索引,不容許使用負數列表索引。
句點查找規則可歸納爲: 當模板系統在變量名中遇到點時,按照如下順序嘗試進行查找:
字典類型查找 (好比 foo["bar"] )
屬性查找 (好比 foo.bar )
方法調用 (好比 foo.bar() )
可使用標準的Python字典語法(syntax)向``上下文(Context)`` 對象添加或者刪除條目:
>>> from django.template import Context >>> c = Context({"foo": "bar"}) >>> c['foo'] 'bar' >>> del c['foo'] >>> c['foo'] Traceback (most recent call last): ... KeyError: 'foo' >>> c['newvariable'] = 'hello' >>> c['newvariable'] 'hello'
----------------------
在Python和Django模板系統中,如下這些對象至關於布爾值的False
空列表([] )
空元組(() )
空字典({} )
空字符串('' )
零值(0 )
特殊對象None
對象False(很明顯)
給定一個運動員列表 athlete_list 變量
{% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %}
給標籤增長一個 reversed 使得該列表被反向迭代:
{% for athlete in athlete_list reversed %} ... {% endfor %}
能夠嵌套使用 {% for %} 標籤
---------------------forloop.parentloop 是一個指向當前循環的上一級循環的 forloop 對象的引用(在嵌套循環的狀況下)。forloop 變量僅僅可以在循環中使用。 在模板解析器碰到 {% endfor %}標籤後, forloop就不可訪問了。
Django模板系統壓根兒就沒想過實現一個全功能的編程語言,因此它不容許咱們在模板中執行Python的語句(仍是那句話,要了解更多請參看理念和限制小節)。 可是比較兩個變量的值而且顯示一些結果實在是個太常見的需求了,因此Django提供了 {% ifequal %} 標籤供咱們使用。
{% ifequal %} 標籤比較兩個值,當他們相等時,顯示在 {% ifequal %} 和 {% endifequal %} 之中全部的值。
下面的例子比較兩個模板變量 user 和 currentuser :
{% ifequal user currentuser %} <h1>Welcome!</h1> {% endifequal %}
注意:
只有模板變量,字符串,整數和小數能夠做爲 {% ifequal %} 標籤的參數。
如下幾個是最爲重要的過濾器的一部分。 附錄F包含其他的過濾器。
addslashes : 添加反斜槓到任何反斜槓、單引號或者雙引號前面。 這在處理包含JavaScript的文本時是很是有用的。
date : 按指定的格式字符串參數格式化 date 或者 datetime 對象, 範例:
{{ pub_date|date:"F j, Y" }}
--------------------
首先考慮把模板保存在文件系統的某個位置並用 Python 內建的文件操做函數來讀取文件內容。 假設文件保存在 /home/djangouser/templates/mytemplate.html 中的話,代碼就會像下面這樣:
from django.template import Template, Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() # Simple way of using templates from the filesystem. # This is BAD because it doesn't account for missing files! fp = open('/home/djangouser/templates/mytemplate.html') t = Template(fp.read()) fp.close() html = t.render(Context({'current_date': now})) return HttpResponse(html)
然而,基於如下幾個緣由,該方法還算不上簡潔:
它沒有對文件丟失的狀況作出處理。 若是文件 mytemplate.html 不存在或者不可讀, open() 函數調用將會引起 IOError 異常。
這裏對模板文件的位置進行了硬編碼。 若是你在每一個視圖函數都用該技術,就要不斷複製這些模板的位置。 更不用說還要帶來大量的輸入工做!
它包含了大量使人生厭的重複代碼。 與其在每次加載模板時都調用 open() 、 fp.read() 和 fp.close() ,還不如作出更佳選擇。
要使用此模板加載API,首先你必須將模板的保存位置告訴框架。
打開你的settings.py配置文件,找到TEMPLATE_DIRS這項設置吧。 它的默認設置是一個空元組(tuple),加上一些自動生成的註釋。
該設置告訴 Django 的模板加載機制在哪裏查找模板。 選擇一個目錄用於存放模板並將其添加到 TEMPLATE_DIRS 中:
TEMPLATE_DIRS = ( '/home/django/mysite/templates', )
若是你的 TEMPLATE_DIRS只包含一個目錄,別忘了在該目錄後加上個逗號。
---------------
(暈菜了)
import MySQLdb
def book_list(request):
db = MySQLdb.connect(user='me', db='mydb', passwd='secret', host='localhost')
cursor = db.cursor()
cursor.execute('SELECT name FROM books ORDER BY name')
names = [row[0] for row in cursor.fetchall()]
db.close()
return render_to_response('book_list.html', {'names': names})
問題:
咱們將數據庫鏈接參數硬行編碼於代碼之中。 理想狀況下,這些參數應當保存在 Django 配置中。
咱們不得不重複一樣的代碼: 建立數據庫鏈接、建立數據庫遊標、執行某個語句、而後關閉數據庫。 理想狀況下,咱們所須要應該只是指定所需的結果。
它把咱們栓死在 MySQL 之上。 若是過段時間,咱們要從 MySQL 換到 PostgreSQL,就不得不使用不一樣的數據庫適配器(例如 psycopg 而不是 MySQLdb ),改變鏈接參數,根據 SQL 語句的類型可能還要修改SQL 。 理想狀況下,應對所使用的數據庫服務器進行抽象,這樣一來只在一處修改便可變換數據庫服務器。 (若是你正在創建一個開源的Django應用程序來儘量讓更多人使用的話,這個特性是很是適當的。)
-------------
Django 裏更關注的是模型(Model)、模板(Template)和視圖(Views),Django 也被稱爲 MTV 框架 。在 MTV 開發模式中:
M 表明模型(Model),即數據存取層。 該層處理與數據相關的全部事務: 如何存取、如何驗證有效性、包含哪些行爲以及數據之間的關係等。
T 表明模板(Template),即表現層。 該層處理與表現相關的決定: 如何在頁面或其餘類型文檔中進行顯示。
DATABASE_ENGINE = '' DATABASE_NAME = '' DATABASE_USER = '' DATABASE_PASSWORD = '' DATABASE_HOST = '' DATABASE_PORT = ''
設置 | 數據庫 | 所需適配器 |
---|---|---|
`` postgresql`` | PostgreSQL | psycopg 1.x版, http://www.djangoproject.com/r/python-pgsql/1/。 |
postgresql_psycopg2 | PostgreSQL | psycopg 2.x版, http://www.djangoproject.com/r/python-pgsql/。 |
mysql | MySQL | MySQLdb , http://www.djangoproject.com/r/python-mysql/. |
sqlite3 | SQLite | 若是使用Python 2.5+則不須要適配器。 不然就使用 pysqlite , http://www.djangoproject.com/r/python-sqlite/。 |
oracle | Oracle | cx_Oracle , http://www.djangoproject.com/r/python-oracle/. |
配置示例:
DATABASE_ENGINE = 'postgresql_psycopg2'
DATABASE_NAME 將數據庫名稱告知 Django 。 例如:
DATABASE_NAME = 'mydb'
若是使用 SQLite,請對數據庫文件指定完整的文件系統路徑。 例如:
DATABASE_NAME = '/home/django/mydata.db'
在這個例子中,咱們將SQLite數據庫放在/home/django目錄下,你能夠任意選用最合適你的目錄。
DATABASE_USER 告訴 Django 用哪一個用戶鏈接數據庫。 例如: 若是用SQLite,空白便可。
DATABASE_PASSWORD 告訴Django鏈接用戶的密碼。 SQLite 用空密碼便可。
DATABASE_HOST 告訴 Django 鏈接哪一臺主機的數據庫服務器。 若是數據庫與 Django 安裝於同一臺計算機(即本機),可將此項保留空白。 若是你使用SQLite,此項留空。
此處的 MySQL 是一個特例。 若是使用的是 MySQL 且該項設置值由斜槓( '/' )開頭,MySQL 將經過 Unix socket 來鏈接指定的套接字,例如:
DATABASE_HOST = '/var/run/mysql'
一旦在輸入了那些設置並保存以後應當測試一下你的配置。 咱們能夠在`` mysite`` 項目目錄下執行上章所提到的`` python manage.py shell`` 來進行測試。 (咱們上一章提到過在,`` manager.py shell`` 命令是以正確Django配置啓用Python交互解釋器的一種方法。 這個方法在這裏是頗有必要的,由於Django須要知道加載哪一個配置文件來獲取數據庫鏈接信息。)
輸入下面這些命令來測試你的數據庫配置:
>>> from django.db import connection >>> cursor = connection.cursor()
錯誤信息 | 解決方法 |
---|---|
You haven’t set the DATABASE_ENGINE setting yet. | 不要以空字符串配置`` DATABASE_ENGINE`` 的值。 表格 5-1 列出可用的值。 |
Environment variable DJANGO_SETTINGS_MODULE is undefined. | 使用`` python manager.py shell`` 命令啓動交互解釋器,不要以`` python`` 命令直接啓動交互解釋器。 |
Error loading _____ module: No module named _____. | 未安裝合適的數據庫適配器 (例如, psycopg 或 MySQLdb )。Django並不自帶適配器,因此你得本身下載安裝。 |
_____ isn’t an available database backend. | 把DATABASE_ENGINE 配置成前面提到的合法的數據庫引擎。 也許是拼寫錯誤? |
database _____ does not exist | 設置`` DATABASE_NAME`` 指向存在的數據庫,或者先在數據庫客戶端中執行合適的`` CREATE DATABASE`` 語句建立數據庫。 |
role _____ does not exist | 設置`` DATABASE_USER`` 指向存在的用戶,或者先在數據庫客戶端中執建立用戶。 |
could not connect to server | 查看DATABASE_HOST和DATABASE_PORT是否已正確配置,並確認數據庫服務器是否已正常運行。 |
若是你只是建造一個簡單的Web站點,那麼可能你只須要一個app就能夠了; 但若是是一個包含許多不相關的模塊的複雜的網站,例如電子商務和社區之類的站點,那麼你可能須要把這些模塊劃分紅不一樣的app,以便之後複用。
系統對app有一個約定: 若是你使用了Django的數據庫層(模型),你 必須建立一個Django app。 模型必須存放在apps中。 所以,爲了開始建造 咱們的模型,咱們必須建立一個新的app。
在`` mysite`` 項目文件下輸入下面的命令來建立`` books`` app:
python manage.py startapp books
from django.db import models class Publisher(models.Model):…… class Author(models.Model):…… class Book(models.Model):……