首先借用書本(book)的這個數(shù)據(jù)模型:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
from django.db import models 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 __unicode__( self ): return self .name class Author(models.Model): first_name = models.CharField(max_length = 30 ) last_name = models.CharField(max_length = 40 ) email = models.EmailField() def __unicode__( self ): return u '%s %s' % ( self .first_name, self .last_name) class Book(models.Model): title = models.CharField(max_length = 100 ) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() def __unicode__( self ): return self .title |
添加字段
當要向一個產(chǎn)品設(shè)置表(或者說是model)添加一個字段的時候,要使用的技巧是利用Django不關(guān)心表里是否包含model里所沒有的列的特性。 策略就是現(xiàn)在數(shù)據(jù)庫里加入字段,然后同步Django的模型以包含新字段。
然而 這里有一個雞生蛋蛋生雞的問題 ,由于要想了解新增列的SQL語句,你需要使用Django的 manage.py sqlall命令進行查看 ,而這又需要字段已經(jīng)在模型里存在了。 (注意:你并 不是非得使用與Django相同的SQL語句創(chuàng)建新的字段,但是這樣做確實是一個好主意 ,它能讓一切都保持同步。)
這個雞-蛋的問題的解決方法是在開發(fā)者環(huán)境里而不是發(fā)布環(huán)境里實現(xiàn)這個變化。 (你正使用的是測試/開發(fā)環(huán)境,對吧?)下面是具體的實施步驟。
首先,進入開發(fā)環(huán)境(也就是說,不是在發(fā)布環(huán)境里):
在你的模型里添加字段。
運行 manage.py sqlall [yourapp] 來測試模型新的 CREATE TABLE 語句。 注意為新字段的列定義。
開啟你的數(shù)據(jù)庫的交互命令界面(比如, psql 或mysql , 或者可以使用 manage.py dbshell )。 執(zhí)行 ALTER TABLE 語句來添加新列。
使用Python的manage.py shell,通過導入模型和選中表單(例如, MyModel.objects.all()[:5] )來驗證新的字段是否被正確的添加 ,如果一切順利,所有的語句都不會報錯。
然后在你的產(chǎn)品服務(wù)器上再實施一遍這些步驟。
啟動數(shù)據(jù)庫的交互界面。
執(zhí)行在開發(fā)環(huán)境步驟中,第三步的ALTER TABLE語句。
將新的字段加入到模型中。 如果你使用了某種版本控制工具,并且在第一步中,已經(jīng)提交了你在開發(fā)環(huán)境上的修改,現(xiàn)在,可以在生產(chǎn)環(huán)境中更新你的代碼了(例如,如果你使用Subversion,執(zhí)行svn update。
重新啟動Web server,使修改生效。
讓我們實踐下,比如添加一個num_pages字段到第五章中Book模型。首先,我們會把開發(fā)環(huán)境中的模型改成如下形式:
1
2
3
4
5
6
7
8
9
|
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 ) * * def __unicode__( self ): return self .title |
然后,我們運行命令manage.py sqlall books 來查看CREATE TABLE語句。 語句的具體內(nèi)容取決與你所使用的數(shù)據(jù)庫, 大概是這個樣子:
1
2
3
4
5
6
7
|
CREATE TABLE "books_book" ( "id" serial NOT NULL PRIMARY KEY , "title" varchar (100) NOT NULL , "publisher_id" integer NOT NULL REFERENCES "books_publisher" ( "id" ), "publication_date" date NOT NULL , "num_pages" integer NULL ); |
新加的字段被這樣表示:
1
|
"num_pages" integer NULL |
接下來,我們要在開發(fā)環(huán)境上運行數(shù)據(jù)庫客戶端,如果是PostgreSQL,運行 psql,,然后,我執(zhí)行如下語句。
1
|
ALTER TABLE books_book ADD COLUMN num_pages integer ; |
添加 非NULL 字段
這里有個微妙之處值得一提。 在我們添加字段num_pages的時候,我們使用了 blank=True 和 null=True 選項。 這是因為在我們第一次創(chuàng)建它的時候,這個數(shù)據(jù)庫字段會含有空值。
然而,想要添加不能含有空值的字段也是可以的。 要想實現(xiàn)這樣的效果,你必須先創(chuàng)建 NULL 型的字段,然后將該字段的值填充為某個默認值,然后再將該字段改為 NOT NULL 型。 例如:
1
2
3
4
5
|
BEGIN ; ALTER TABLE books_book ADD COLUMN num_pages integer ; UPDATE books_book SET num_pages=0; ALTER TABLE books_book ALTER COLUMN num_pages SET NOT NULL ; COMMIT ; |
如果你這樣做,記得你不要在模型中添加 blank=True 和 null=True 選項。
執(zhí)行ALTER TABLE之后,我們要驗證一下修改結(jié)果是否正確。啟動python并執(zhí)行下面的代碼:
1
2
|
>>> from mysite.books.models import Book >>> Book.objects. all ()[: 5 ] |
如果沒有異常發(fā)生,我們將切換到生產(chǎn)服務(wù)器,然后在生產(chǎn)環(huán)境的數(shù)據(jù)庫中執(zhí)行命令A(yù)LTER TABLE 然后我們更新生產(chǎn)環(huán)境中的模型,最后重啟web服務(wù)器。