在當今的Web 應用中,主觀邏輯常常牽涉到與數據庫的交互,數據庫驅動網站。在後臺鏈接數據庫服務器,從中取出一些數據,而後在 Web 頁面用各類各樣的格式展現這些數據。這個網站也可能會向訪問者提供修改數據庫數據的方法。html
本章深刻介紹了該功能: Django 數據庫層。本例咱們使用Python安裝包自帶的SQLite數據庫來演示Django如何訪問數據庫。python
首先咱們使用數據庫訪問工具Navicat premium來在mysite目錄下建立SQLite數據庫文件。Navicat premium下載地址http://navicat-premium.softonic.cn/mysql
運行Navicat premium工具,在主界面的菜單中選擇文件->新建鏈接-SQLite以下圖:sql
在對話框中選擇新建SQLite3數據庫文件,數據庫文件名命名爲:MyDB.db後點擊肯定按鈕。以下圖:shell
數據庫文件鏈接後,界面展開以下圖:數據庫
如今咱們能夠經過執行SQL的方式來訪問數據庫,獲取數據並更新到咱們的動態頁面中,修改views.py把current_datetime視圖獲取時間的方式修改成經過執行SQL 「select datetime() as now」讀取數據庫的時間,修改後代碼以下:django
from django.shortcuts import render_to_response import sqlite3 def current_datetime(request): db = sqlite3.connect('C:\My Files\Python Projects\mysite\Mydb.db') cursor = db.cursor() cursor.execute('select datetime() as now') now = [row[0] for row in cursor.fetchall()] db.close() return render_to_response('current_datetime.html', {'current_date': now})
如上代碼,我是通過代碼重構,current_datetime實現了讀取數據庫的當前時間,可是這種把SQL與業務邏輯徹底綁定的開發模式會存爲未來維護和升級的噩夢。業務變動致使的業務邏輯調整,進而須要調整到SQL代碼,最後就與數據庫設計深度綁定,尤爲切換數據庫時因爲各個數據庫支持的SQL不徹底一致,應用的遷移將花費的代價更大。服務器
好在Django提供了本身的對象持久化模型,實現了對象模型到數據庫表的映射機制,接下來咱們進入Django的對象模型來實現數據庫數據的讀取。session
Django 牢牢地遵循這種 MVC 模式,能夠稱得上是一種 MVC 框架。MVC 是一種使用 MVC(Model View Controller 模型-視圖-控制器)設計建立 Web 應用程序的模式。oracle
咱們來看看 Django 數據庫模型層的功能吧。 首先,須要作些初始配置;須要告訴Django使用什麼數據庫以及如何鏈接數據庫。本例咱們使用SQLite數據庫文件系統來存儲數據。
如前面章節提到的 TEMPLATE_DIRS 同樣,數據庫配置也是在Django的配置文件settings.py裏。默認生成的數據庫配置以下:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 'NAME': '', # Or path to database file if using sqlite3. 'USER': '', # Not used with sqlite3. 'PASSWORD': '', # Not used with sqlite3. 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. 'PORT': '', # Set to empty string for default. Not used with sqlite3. } }
修改配置文件以下:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends. sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 'NAME': ' C:\My Files\Python Projects\mysite\MyDB.db', # Or path to database file if using sqlite3. 'USER': '', # Not used with sqlite3. 'PASSWORD': '', # Not used with sqlite3. 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. 'PORT': '', # Set to empty string for default. Not used with sqlite3. } }
完成設置並保存以後咱們測試一下配置。 一樣,在「mysite」項目目錄下執行前面提到的「python manage.py shell」環境來進行測試。
輸入下面的命令來測試數據庫配置是否正確:
>>> from django.db import connection >>> cursor = connection.cursor()
若是沒有顯示什麼錯誤信息,那麼數據庫配置是正確的。
數據庫鏈接正常工做後,讓咱們來建立一個 Django app,一個包含模型,視圖和Django代碼,而且形式爲獨立Python包的完整Django應用。
在這裏先解釋說明一些術語,初學者可能會混淆它們。在第二章咱們已經建立了一個project,那麼 project 和 app 之間不一樣之處是什麼呢?它們的區別就是一個是配置另外一個是業務代碼。
一個project包含不少個Django app。project的做用是提供這些應用統一配置文件,好比前面定義數據庫鏈接信息, 須要裝載的app列表,TEMPLATE_DIRS等。
一個app是一套業務功能的集合,一般包括模型和視圖,按Python的包結構的方式存在。app的一個關鍵點是它們是很容易移植到其餘project和被多個project複用。
Django系統對app有一個約定: 要使用Django的數據庫層(模型),必須建立一個Django app,模型存放在apps中。在 「mysite」 項目文件下輸入下面的命令來建立「inventory」的app,本例將以簡單出入庫業務來講明Django的模型。
>>> python manage.py startapp inventory
增長子目錄及子目錄inventory 包含文件以下圖:
inventory / __init__.py models.py tests.py views.py
在本章和後續章節裏,咱們將實現一個基本的庫存管理(庫存/出入庫)的數據庫結構上,這也是一個做者遇到過的比較典型關於業務及業務事務的例子。
庫存管理涉及的基本概念、字段和關係:
物料:物料編號、物料名稱、備註。
物料庫存:物料編號、物料名稱、庫存數量。
入庫單:入庫單編號、入庫時間、操做人,物料編碼、物料名稱、入庫數量。
注意:本模型爲便於闡述簡化設計入庫單爲單一物料入庫單,後面的章節咱們會逐步擴展這一模型以符合實際的須要。
物料與物料庫存是一個one-to-one關係, 對於入庫單模型來講其與物料的關係是many-to-many關係。
接下來咱們用Python代碼來描述它們。 打開由建立的inventory \models.py 並輸入下面的內容:
from django.db import models # Create your models here. class Item(models.Model): ItemId = models.AutoField(primary_key=True) ItemCode = models.CharField(max_length=50)
ItemName = models.CharField(max_length=50) Remark = models.CharField(max_length=200) class Inventory (models.Model): InventoryId = models.AutoField(primary_key=True) Item = models.ForeignKey(Item, null=False) Amount = models.IntegerField(null=True) class InStockBill(models.Model): InStockBillId = models.AutoField(primary_key=True) InStockBillCode = models.CharField(max_length=40) InStockDate = models.DateTimeField(null=True) Operator = models.CharField(max_length=40) Item = models.ForeignKey(Item, null=False) Amount = models.IntegerField(null=True)
完成上面的模型代碼後,如今讓咱們經過Django在數據庫中建立這些表。第一步是在 Django 項目中裝載這些模型。 將 inventory app 添加到配置文件的裝載應用列表中便可。
編輯 settings.py 文件, 找到 INSTALLED_APPS 設置。 INSTALLED_APPS 告訴 Django 項目須要裝載哪些 app模型。 缺省生成代碼在後面添加「inventory」到「INSTALLED_APPS」的末尾,注意:只配置應用名稱,沒有項目名稱,代碼以下:
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', 'inventory', )
如今咱們能夠建立數據庫表了。 首先,用下面的命令驗證模型的有效性:
python manage.py validate
validate 命令檢查你的模型的語法和邏輯是否正確。 若是一切正常,你會看到 0 errors found 消息。若是出錯,根據錯誤信息來幫助你修正你的模型。
python manage.py sqlall inventory
執行以後,輸出以下:
BEGIN; CREATE TABLE "inventory_item" ( "ItemId" integer NOT NULL PRIMARY KEY, "ItemCode" varchar(50) NOT NULL, "ItemName" varchar(50) NOT NULL ); CREATE TABLE "inventory_inventory" ( "InventoryId" integer NOT NULL PRIMARY KEY, "Item_id" integer NOT NULL REFERENCES "inventory_item" ("ItemId"), "Amount" integer ); CREATE TABLE "inventory_instockbill" ( "InStockBillId" integer NOT NULL PRIMARY KEY, "InStockBillCode" varchar(40) NOT NULL, "InStockDate" datetime, "Operator" varchar(40) NOT NULL, "Item_id" integer NOT NULL REFERENCES "inventory_item" ("ItemId"), "Amount" integer ); CREATE INDEX "inventory_inventory_70e6447b" ON "inventory_inventory" ("Item_id"); CREATE INDEX "inventory_instockbill_70e6447b" ON "inventory_instockbill" ("Item_id"); COMMIT;
sqlall 命令並無在數據庫中真正建立數據表,只是把SQL語句段打印出來,這樣你能夠看到Django究竟會作些什麼。
Django提供了一種更爲簡易的提交SQL語句至數據庫的方法:「syncdb」命令
python manage.py syncdb
syncdb 命令是同步你的模型到數據庫的一個簡單方法。 它會根據 INSTALLED_APPS 裏設置的app來檢查數據庫, 若是表不存在,它就會建立它。
表建立結果以下圖:
運行 python manage.py shell 並輸入下面的內容試試看
>>> from inventory.models import Item >>> itm1 = Item(ItemCode='003',ItemName='螺帽') >>> itm1.save()
咱們查看數據庫看發生了什麼,物料數據被保存到數據庫中了,以下圖:
咱們在數據庫工具端增長一條記錄:000,螺桿以下圖:
接下來再命令行窗口中錄入以下命令:
>>> items =Item.objects.all() >>> print items[1].ItemName 螺桿 >>>
咱們經過Item.objects.all()獲取了全部的Item列表數據(當前只有兩條)。
>>> itm2 = Item.objects.get(ItemId = 2) >>> print itm2.ItemName 螺桿 >>> itm2.ItemName=u'5mm螺桿' >>> itm2.save() >>>
修改對象屬性後,保存數據,對象屬性會同步到相應的數據行。
咱們建立一個入庫單對象,並嘗試如何正確的保存該對象到數據庫中,命令以下:
>>> from inventory.models import Item >>> from inventory.models import InStockBill >>> inStock = InStockBill(InStockBillCode='20141101001',InStockDate='2014-11-01',Operator='張三',Amount=10) >>> inStock.save()
在沒有賦值給InStockBill屬性Item的狀況下咱們直接調用保存函數會報錯,數據不能正常提交到數據庫中。
>>> inStock.Item = 1
咱們直接給inStock.Item 賦值1(Itemid=1的物料在咱們的例子中是前面保存進數據庫的「螺母」),也會報錯,雖然在數據庫裏,InStockBill表外鍵關係存儲的是關聯表的主鍵。須要inStock.Item賦值爲一個具體的Item模型才能正常的提交數據。Django在這裏已經把表映射爲對象了。注:本例中入庫單保存成功的同時,應該更新庫存表數據(入庫單將致使該物料庫存數量增長)後面咱們將在業務事物章節說明。
>>> item1 = Item.objects.get(ItemId=1) >>> inStock.Item =item1 >>> inStock.save() >>>
這裏咱們會看見數據保存到數據庫中後,入庫時間變成了2014-10-31 16:00:00,這是由於settings.py時區設置爲:TIME_ZONE = 'America/Chicago'的緣故,把USE_TZ = True修改成便可USE_TZ = False:
# If you set this to False, Django will not use timezone-aware datetimes. USE_TZ = False
在你的 Django 應用中,你或許但願根據某字段的值對檢索結果排序,好比說,按字母順序。 那麼,使用 order_by() 這個方法就能夠搞定了。
>>> itms = Item.objects.all() >>> print itms[0].ItemCode 003 >>> itms = Item.objects.order_by('ItemCode')
>>> print itms[0].ItemCode
000
Django指定模型的缺省排序方式,在模型配置中配置
class Item(models.Model): ItemId = models.AutoField(primary_key=True) ItemCode = models.CharField(max_length=50) ItemName = models.CharField(max_length=50) class Meta: ordering = ['ItemCode']
>>> itm2 = Item.objects.get(ItemId = 2) >>> itm2.delete() >>>
本章咱們經過一個簡單的實例模型例子來講Django模型如何建立、配置和訪問數據庫等。並經過Python環境演示了模型的裝載、訪問、查詢、保存、排序和刪除等操做。
下一章咱們將介紹Django是如何實現經過客戶端向服務端提交數據——表單。