Djangon第五篇-----模型詳解
目錄
前言
對現代的 Web 應用程式而言,檢視邏輯經常需要與資料庫互動。在資料庫驅動型網站中,網站連線資料庫伺服器,從中檢索資料,然後在網頁中把資料顯示出來。此外,可能還會提供讓訪客自行填充資料庫的方式。Django 非常適合構建資料庫驅動型網站,它提供了簡單而強大的工具,易於使用 Python 執行資料庫查詢。下面就說明這個功能,即 Django 的資料庫層。
配置資料庫
settings.py
# Database
# ...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
• ENGINE 告訴 Django 使用哪個資料庫引擎。本書的示例使用 SQLite,因此不用改,繼續使用預設的
django.db.backends.sqlite3 。
• NAME 告訴 Django 資料庫的名稱。例如: 'NAME': 'mydb', 。
使用 Python 定義模型的好處
• 內省(introspection)有開銷,而且不完美。為了提供便利的資料訪問 API,Django 需要以某種方式知曉資料庫佈局,而這一需求有兩種實現方式。第一種是使用 Python 明確描述資料,第二種是在執行時內省資料庫,推知資料模型。第二種方式在一個地方儲存表的元資料,看似更簡單,其實會導致幾個問題。首先,執行時內省資料庫肯定有消耗。如果每次執行請求,或者只是初始化 Web 伺服器都要內省資料庫,那帶來的消耗是無法接受的。(有些人覺那點消耗不算事,然而 Django 的開發者可是在想方設法努力降低框架的消耗。)其次,有些資料庫,尤其是舊版 MySQL,儲存的元資料不足以完成內省。
• Python 編寫起來讓人心情舒暢,而且使用 Python 編寫所有程式碼無需頻繁讓大腦切換情境。在一個程式設計環境(思維)中待久了,有助於提升效率。在 SQL 和 Python 之間換來換去容易打斷狀態
• 把資料模型儲存在程式碼中比儲存在資料庫中易於做版本控制,易於跟蹤資料佈局的變化。
• SQL 對資料佈局的元資料只有部分支援。例如,多數資料庫系統沒有提供專門表示電子郵件地址或URL 的資料型別。而 Django 模型有。高層級的資料結構有助於提升效率,讓程式碼更便於複用。
• 不同資料庫平臺使用的 SQL 不一致。分發 Web 應用程式時,更務實的做法是分發一個描述資料佈局的 Python 模組,而不是分別針對MySQL、PostgreSQL 和 SQLite 的 CREATE TABLE 語句。
建立模型
在編譯器命令列執行或定位到專案根目錄
django-admin startapp books
models.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
# Create your models here.
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField()
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
settings.py 新增books模型
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'books',
)
檢查框架,如下即可
python manage.py check
確認模型有效之後,執行下述命令,告訴 Django 你對模型做了修改(這裡是新建了模型):
python manage.py makemigrations books
Django 把對模型(也就是資料庫模式)的改動儲存在遷移中,遷移就是磁碟中的檔案。執行上述命令後,books 應用的 migrations 資料夾裡會出現一個名為 0001_initial.py 的檔案。 migrate 命令會檢視最新的遷移檔案,自動更新資料庫模式;不過,我們先來看看將執行的 SQL。 sqlmigrate 命令的引數是遷移名稱,輸出的結果是對應的 SQL:
python manage.py sqlmigrate books 0001
• 自動生成的表名結合應用的名稱( books )和模型名的小寫形式( publisher 、 book 和 author )。
• 前面說過,Django 會自動為各個表新增主鍵,即 id 欄位。這個行為可以覆蓋。按約定,Django 在外來鍵欄位的名稱後面加上 "_id" 。你可能猜到了,這個行為也可以覆蓋。
• 外來鍵關係通過 REFERENCES 語句指明。
sqlmigrate 命令並不建立表,其實它根本不接觸資料庫,而是在螢幕上輸出 Django 將執行的 SQL。如果願意,可以把輸出的 SQL 複製貼上到資料庫客戶端裡,然而,Django 為提交 SQL 提供了更為簡單的方式
python manage.py migrate
資料的基本訪問
建立模型之後,Django 自動提供了操作模型的高層 Python API。執行 python manage.py shell ,輸入下述程式碼試試:
>>> from books.models import Publisher
>>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue',
... city='Berkeley', state_province='CA', country='U.S.A.',
... website='http://www.apress.com/')
>>> p1.save()
>>> p2 = Publisher(name="O'Reilly", address='10 Fawcett St.',
... city='Cambridge', state_province='MA', country='U.S.A.',
... website='http://www.oreilly.com/')
>>> p2.save()
>>> publisher_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: Publisher object>, <Publisher: Publisher object>]
主要功能如下:
• 首先,匯入 Publisher 模型類,以便與儲存出版社的資料庫表互動。
• 提供各個欄位的值, name 、 address ,等等,例項化一個 Publisher 物件。
• 為了把物件儲存到資料庫中,呼叫 save() 方法。Django 在背後執行 SQL INSERT 語句。
• 為了從資料庫中檢索出版社,使用 Publisher.objects 屬性,你可以把它的值理解為全部出版社。使用 Publisher.objects.all() 獲取資料庫中的所有 Publisher 物件。Django 在背後執行 SQL SELECT 語句
使用 Django 模型 API 建立的物件不會自動儲存,只能自己動手呼叫 save() 方法
為 Publisher 類新增一個名為 __str__() 的方法可改變publisher_list輸出內容,如
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
def __str__(self):
return self.name
插入和更新資料
>>> from books.models import Publisher
>>> p = Publisher(name='1',address='qwe',city ='bb',state_province='ca',country='usa',website='sda')
>>> p.save()
>>> p.id
1
>>> p.id = 111
>>> p.id
111
>>> p.save()
過濾資料
也可以傳遞多個引數
>>> Publisher.objects.filter(id=1)
<QuerySet [<Publisher: 1>]>
檢索單個物件
>>> Publisher.objects.get(id=1)
<Publisher: 1>
排序資料
Publisher.objects.order_by("name")
多個欄位排序(以第一個欄位排不出順序時使用第二個欄位),提供多個引數:
>>> Publisher.objects.order_by("state_province", "address")
反向排序。方法是在欄位名稱前面加上“-”(減號):
Publisher.objects.order_by("-name")
鏈式查詢
過濾資料同時排序資料
Publisher.objects.filter(country="U.S.A.").order_by("-name")
切片資料
只顯示第一個
Publisher.objects.order_by('name')[0]
範圍切片
Publisher.objects.order_by('name')[0:2]
注意,不支援使用負數:可以換成一下形式
Publisher.objects.order_by('-name')[0]
在一個語句中更新多個物件
Publisher.objects.filter(id=52).update(name='Apress Publishing')
Publisher.objects.all().update(country='USA')
刪除物件
刪除所有
Publisher.objects.all().delete()
刪除部分
Publisher.objects.filter(country='USA').delete()