1. 程式人生 > >Djangon第五篇-----模型詳解

Djangon第五篇-----模型詳解

目錄

前言

配置資料庫

使用 Python 定義模型的好處

建立模型

資料的基本訪問

插入和更新資料

 過濾資料

 檢索單個物件

排序資料

 鏈式查詢

 切片資料

在一個語句中更新多個物件

 刪除物件


前言

對現代的 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()