Django Book 2.0 筆記——Model

配置數據庫:

settings 文件內:python

  
DATABASES = { ' default ' : { ' ENGINE ' : ' django.db.backends.postgresql_psycopg2 ' , ' NAME ' : ' mydatabase ' , ' USER ' : ' mydatabaseuser ' , ' PASSWORD ' : ' mypassword ' , ' HOST ' : ' 127.0.0.1 ' , ' PORT ' : ' 5432 ' , } }

若是是 SQLite,則只需填寫 engine 和 name,SQLite 的 name 應當包含可靠路徑(由於沒有 server):web

  
DATABASES = { ' default ' : { ' ENGINE ' : ' django.db.backends.sqlite3 ' , ' NAME ' : ' mydatabase ' , } }

測試數據庫配置:sql

  
>>> from django.db import connection >>> cursor = connection.cursor()

 

建立表

django 的 ORM 示例,定義在 app 下的 models 文件內,具體支持的字段參考官方文檔:shell

  
from django.db import models class Book(models.Model): title = models.CharField(max_length = 100 ) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField()

django 使用額外一張單獨的表來管理多對多聯繫。數據庫

 

部署模型

在部署模型前,首先應保證相應的 app 是已安裝狀態,這在 settings 文件內的 INSTALLED_APPS 字段內進行設置。django

 

驗證模型有效性:

  
python manage.py validate

 

生成 CREAT TABLE 語句(打印出來給你看看,並不執行):

  
python manage.py sqlall books

這裏的 books 是 app 的名稱。運行後輸出以下:安全

  
BEGIN ; CREATE TABLE "books_publisher" ( "id" serial NOT NULL PRIMARY KEY , "name" varchar ( 30 ) NOT NULL , "address" varchar ( 50 ) NOT NULL , "city" varchar ( 60 ) NOT NULL , "state_province" varchar ( 30 ) NOT NULL , "country" varchar ( 50 ) NOT NULL , "website" varchar ( 200 ) NOT NULL ) ; CREATE TABLE "books_author" ( "id" serial NOT NULL PRIMARY KEY , "first_name" varchar ( 30 ) NOT NULL , "last_name" varchar ( 40 ) NOT NULL , "email" varchar ( 75 ) NOT NULL ) ; CREATE TABLE "books_book" ( "id" serial NOT NULL PRIMARY KEY , "title" varchar ( 100 ) NOT NULL , "publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id") DEFERRABLE INITIALLY DEFERRED, "publication_date" date NOT NULL ) ; CREATE TABLE "books_book_authors" ( "id" serial NOT NULL PRIMARY KEY , "book_id" integer NOT NULL REFERENCES "books_book" ("id") DEFERRABLE INITIALLY DEFERRED, "author_id" integer NOT NULL REFERENCES "books_author" ("id") DEFERRABLE INITIALLY DEFERRED, UNIQUE ("book_id", "author_id") ) ; CREATE INDEX "books_book_publisher_id" ON "books_book" ("publisher_id"); COMMIT ;

注意:app

  • 這裏自動生成的表名是:app名稱( books )和模型的小寫名稱 ( publisher , book , author )的組合。除非你顯式指定一個表名。
  • Django爲每一個表格自動添加加了一個 id 主鍵, 你能夠從新設置它。
  • 按約定,Django添加 "_id" 後綴到外鍵字段名,這個一樣是可自定義的
  • 外鍵是用 REFERENCES 語句明肯定義的(books 的 publisher 外鍵)
  • 這些 CREATE TABLE 語句會根據你的數據庫而做調整

 

同步數據庫(僅添加,不會修改和刪除表):

  
python manage.py syncdb

 

INSERT & UPDATE:

在 python manage.py shell 命令行內執行 INSERT 操做的方法是實例化一個模型對象,並調用其 .save() 方法post

  
>>> 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()

不過這個 save() 方法在用於 UPDATE 功能時,實際執行的是更新整行而不只是修改過的屬性。這可能會引發競態條件,若是想只更新一個屬性,應當調用結果集的 .update() 方法:測試

  
>>> Publisher.objects.filter(id = 52 ).update(name = ' Apress Publishing ' )

update() 方法返回一個整數,表示受影響的行數。

 

DELETE:

.delete() 方法與 .update() 相似,都是做用於結果集的方法。但出於安全考慮,在刪除表中全部元組時,須要顯示調用 .all() 方法:

  
>>> Publisher.objects.delete() Traceback (most recent call last): File " <console> " , line 1 , in < module > AttributeError: ' Manager ' object has no attribute ' delete ' >>> Publisher.objects.all().delete()

 

SELECT:

若是想 print 出 Publisher 對象的內容,須要在定義模型時寫好 __str__() 方法。

  
>>> publisher_list = Publisher.objects.all() >>> publisher_list [ < Publisher: Publisher object > , < Publisher: Publisher object > ]

 

WHERE:

  
>>> Publisher.objects.filter(name = ' Apress ' [, *** ]) [ < Publisher: Apress > ]

 

LIKE:

注意這裏是雙下劃線 __contains

  
>>> Publisher.objects.filter(name__contains = " press " ) [ < Publisher: Apress > ]

filter() 返回的老是一個容器對象,這個對象實現了列表的操做方法(一如既往不包括負索引),所以老是可使用好比 for 循環來迭代其中的元素。對應的有一個 get() 方法,這個方法要求知足條件的元素有且只有一個,不然引起異常。

 

給結果排序:

  
>>> Publisher.objects.order_by( " state_province " , " address " )

第二個參數僅在第一個參數相同時起做用,排序還能夠在屬性前加「-」來實現逆序:

  
>>> Publisher.objects.order_by( " -name " )

.ordered_by() 可做用於結果查詢結果對象集,因此 filter() 返回的結果也能夠支持。

或者,直接在模型定義的地方指定默認排序方式:

  
class Publisher(models.Model): name = models.CharField(max_length = 30 ) . . . class Meta: ordering = [ ' name ' ]

 

訪問外鍵(Foreign Key)值:

當訪問外鍵字段時,會獲得相應的模型對象:

  
>>> b = Book.objects.get(id = 50 ) >>> b.publisher < Publisher: Apress Publishing > >>> b.publisher.website u ' http://www.apress.com/ '

而當經過外鍵反向追溯時,則會得到一個模型對象的 QuerySet,這個對象與前面同樣也支持過濾和分切操做。實現這類訪問使用的屬性名是由模型名稱的小寫 + _set 組成的:

  
>>> p = Publisher.objects.get(name = ' Apress Publishing ' ) >>> p.book_set.all() [ < Book: The Django Book > , < Book: Dive Into Python > , ...] >>> p.book_set.filter(name__icontains = ' django ' ) [ < Book: The Django Book > , < Book: Pro Django > ]

 

訪問多對多值:

多對多和外鍵工做方式相同,只不過處理的是QuerySet而不是模型實例:

  
>>> b = Book.objects.get(id = 50 ) >>> b.authors.all() [ < Author: Adrian Holovaty > , < Author: Jacob Kaplan - Moss > ] >>> b.authors.filter(first_name = ' Adrian ' ) [ < Author: Adrian Holovaty > ] >>> b.authors.filter(first_name = ' Adam ' ) []

反向查詢也能夠。 要查看一個做者的全部書籍,使用author.book_set ,就如這樣:

  
>>> a = Author.objects.get(first_name = ' Adrian ' , last_name = ' Holovaty ' ) >>> a.book_set.all() [ < Book: The Django Book > , < Book: Adrian ' s Other Book>]

 

更改數據庫模式(DB schema):

先前提到過,syncdb 命令只添加新表,並不會把已有模型的更新同步到數據庫中。實際上,django 對已有 模型 與 數據庫 之間的對應關係僅做最低限度的檢查——即:模型中的字段在數據庫中必須有,不然會引起運行時錯誤(在用戶進行查詢的時候);至於數據庫中是否存在模型裏並未定義的字段,django 並不關心,由於數據庫中多餘的字段並不影響 django 依據模型作正常的查詢。(django 在作 orm 到 sql 語句的轉化時,老是會明確指出要查詢的字段)

基於這種邏輯,想要修改數據庫模式應該採用的方法就是:在不引起運行時錯誤的前提下,按特定順序分別修改數據庫和模型。具體順序爲:

  • 添加字段時:先在開發者環境下修改模型,並經過 sqlall 命令查看修改模型須要使用的 sql 語句,修改數據庫與模型並測試經過。而後去部署環境提交這條語句以修改數據庫,以後在部署環境修改模型,最後重啓 server,使修改生效。這裏利用 sqlall 刻意使用了 django 生成的 sql 語句,但這並非必須的,這只是一個好習慣,若是命令簡單,也徹底能夠本身寫這條 sql 命令,但在開發環境下進行測試仍是不可少的
  • 添加非 NULL 字段時:由於新添加的字段老是空的,因此若是須要添加非 NULL 字段,就要先添加如 IntegerField(blank=True,null=True) 這樣的容許空值字段,而後給他們賦值,再把它們改爲非 NULL 字段。
  • 刪除字段時:這時的操做順序與添加字段相反,必須先修改模型,再修改數據庫。
  • 刪除多對多聯繫時:先在模型中刪除多對多字段,而後在數據庫中刪除多對多關係表(前面提到過,django 用一張單獨的表管理多對多聯繫)。語句形如:DROP TABLE books_book_authors; (最前面的 books 是 app 名)
  • 刪除模型時:從 models 文件中刪除模型,而後從數據庫中刪除表:DROP TABLE books_book; 另外,若是其餘表有指向這張表的外鍵,那麼你得先把那些表刪了...

 

Managers

在形如 Book.objects.all() 的語句中,objects 做爲 models.Model 類的一個特殊屬性,他是 models.Manager 的實例。有些時候咱們能夠經過自定義這個屬性來實現一些特別的方法,或修改 manager 返回的 QuerySets 。

 

增長額外的Manager方法:

這須要子類化一個 Manager 對象,再把它綁定到具體的模型中,好比:

  
# models.py from django.db import models # ... Author and Publisher models here ... class BookManager(models.Manager): def title_count(self, keyword): return self.filter(title__icontains = keyword).count() class Book(models.Model): title = models.CharField(max_length = 100 ) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() num_pages = models.IntegerField(blank = True, null = True) objects = BookManager() def __unicode__ (self): return self.title

有了這個manager,咱們如今能夠這樣作:

  
>>> Book.objects.title_count( ' django ' ) 4 >>> Book.objects.title_count( ' python ' ) 18

 

修改初始Manager QuerySets:

manager的基本QuerySet返回系統中的全部對象。 例如,`` Book.objects.all()`` 返回數據庫book中的全部書本。咱們能夠經過覆蓋Manager.get_query_set()方法來重寫manager的基本QuerySet。 get_query_set()按照你的要求返回一個QuerySet。

  
from django.db import models # First, define the Manager subclass. class DahlBookManager(models.Manager): def get_query_set(self): return super(DahlBookManager, self).get_query_set().filter(author = ' Roald Dahl ' ) # Then hook it into the Book model explicitly. class Book(models.Model): title = models.CharField(max_length = 100 ) author = models.CharField(max_length = 50 ) # ... objects = models.Manager() # The default manager. dahl_objects = DahlBookManager() # The Dahl-specific manager.

在這個示例模型中,Book.objects.all()返回了數據庫中的全部書本,而Book.dahl_objects.all()只返回了Roald Dahl的書。

這個例子也說明了另一件事情,就是一個模型能夠有多個 manager 屬性。你只須要給他們作好命名就能夠了(不要再用 objects)。

注意:django 會把模型中定義的第一個 manager 做爲默認 manager 使用,若是你重寫了任何一個 manager 的話。因此當你給模型添加 manager 的時候,必定記得在最前面把 models.Manager 綁定給 objects 。

 

模型方法:

模型方法就是模型裏定義的方法,跟普通類裏定義的方法沒什麼不一樣。

 

執行原始 SQL 查詢:

使用 DB-API 便可。

相關文章
相關標籤/搜索