1. 程式人生 > >django 資料庫增強工具 south 的安裝使用和注意事項。。。

django 資料庫增強工具 south 的安裝使用和注意事項。。。

django 開發 web 應用的時候,其中的 ORM 非常好用。 通過 moldes 的定義和呼叫。可是,django 在 資料庫同步 (syncdb) 的時候。只會建立不存在的資料表。對於中途需要修改 model ,比如增加欄位,刪除欄位,修改欄位等操作  syncdb是 不會對資料庫有任何更改。

此時,使用 south 可以達到 修改 models 的時候, 自動更改資料庫表結構。

south的安裝

​安裝 south 很簡單

pip install south

新增 south 到專案中

對於 新增 south 到專案中,主要有三種情況。參考 stackoverflow 上的總結 如下:

1)建立一個沒有資料庫的新專案時


    1、建立資料庫 ,將south新增到INSTALLED_APPS


    2、執行syncdb命令,它將django和south的資料表加入到資料庫中。每次執行 syncdb 之後,都執行  python manage.py migrate 進行一次


    3、然後將你建立的apps新增到 INSTALLED_APPS


    5、對每個app分別執行 “python manage.py schemamigration app_name --initial”,它將在每個app的目錄下建立migration目錄和相應的檔案。


    6、然後執行“python manage.py migrate app_name”,這一步將app的資料表加入到資料庫中

2)在帶有資料庫的已存專案中使用south


    1、將south加入到INSTALLED_APPS中


    2、執行syncdb,它將south的資料表加入到資料庫中


    3、對每個app分別執行python manage.py schemamigration app_name --initial,它將在每個app的目錄下建立migration目錄和相應的檔案


    4、對每個app分別執行“python manage.py migrate app_name 0001 --fake”,該命令不會對資料庫做任何操作,只是欺騙一下south,讓它在south_migrationhistory表中新增一些記錄以便於下次你想創造migration檔案的時候所有東西都已搞定。


  3、在沒有資料庫的已存專案中使用south


    1)建立資料庫


    2)將south加入到INSTALLED_APPS中


    3)對每個app分別執行“ python manage.py schemamigration app_name --initial”,它將在每個app的目錄下建立migration目錄和相應的檔案


    4)執行syncdb,它將所有沒有migrations的apps加入到資料庫中


    5)然後執行“python manage.py migrate”命令,它將對你的所有apps執行遷移操作。

使用 south

安裝遷移 south 之後,就是使用。主要有兩個命令 

每次更改 models 之後執行 

python manage.py schemamigration app_name --auto

會看到 model 修改了那些屬性

然後執行

python manage.py migrate app_name

會將更改同步到資料庫中

實戰

增加一個欄位

例如我的 初始 model 如下 

class User(models.Model):

    username = models.CharField(max_length=20, unique=True)
    password = models.CharField(max_length=40)
    email = models.EmailField(max_length=80, unique=True)

此時需要新增一個 test 欄位 ,更改 model 如下 

class User(models.Model):

    username = models.CharField(max_length=20, unique=True)
    password = models.CharField(max_length=40)
    email = models.EmailField(max_length=80, unique=True)

    test = models.CharField(max_length=10)

更改之後執行 


python manage.py schemamigration app_name --auto

1 .此時會有兩種情況,如果資料庫本身沒有記錄,就直接執行結束。這種情況比較少見. 

2 第二種情況是資料表已經存在記錄。比如我存在一條記錄  usname= rsj217  password=111 [email protected]  會出現下面這個 

(pythonenv)[email protected]:~/project/python/vitrual/dblog$ python manage.py schemamigration blog --auto
 ? The field 'User.test' does not have a default specified, yet is NOT NULL.
 ? Since you are adding this field, you MUST specify a default
 ? value to use for existing rows. Would you like to:
 ?  1. Quit now, and add a default to the field in models.py
 ?  2. Specify a one-off value to use for existing columns now
 ? Please select a choice: 

也就是 需要增加一個欄位 test,原來的資料表有一條記錄是沒有這個欄位的,並且這個欄位還不能是空。一旦添加了欄位,原來的記錄要想保持正確,就必須要手動指定。有兩個選項,第一個放棄操作,新增一個預設的欄位在 models。第二個選項是 手動指定一個欄位 (columns)。這裡我們選擇 2,會顯示如下
(pythonenv)[email protected]:~/project/python/vitrual/dblog$ python manage.py schemamigration blog --auto
 ? The field 'User.test' does not have a default specified, yet is NOT NULL.
 ? Since you are adding this field, you MUST specify a default
 ? value to use for existing rows. Would you like to:
 ?  1. Quit now, and add a default to the field in models.py
 ?  2. Specify a one-off value to use for existing columns now
 ? Please select a choice: 2
 ? Please enter Python code for your one-off default value.
 ? The datetime module is available, so you can do e.g. datetime.date.today()
 >>> 

此時只要給已經存在的記錄手動指定欄位的值就行  輸入 'test' 如一下
(pythonenv)[email protected]:~/project/python/vitrual/dblog$ python manage.py schemamigration blog --auto
 ? The field 'User.test' does not have a default specified, yet is NOT NULL.
 ? Since you are adding this field, you MUST specify a default
 ? value to use for existing rows. Would you like to:
 ?  1. Quit now, and add a default to the field in models.py
 ?  2. Specify a one-off value to use for existing columns now
 ? Please select a choice: 2
 ? Please enter Python code for your one-off default value.
 ? The datetime module is available, so you can do e.g. datetime.date.today()
 >>> 'test'
 + Added field test on blog.User
Created 0008_auto__add_field_user_test.py. You can now apply this migration with: ./manage.py migrate blog

此時 ,再執行 
python manage.py migrate app_name

得到下面的提示 

(pythonenv)[email protected]:~/project/python/vitrual/dblog$ python manage.py migrate blog
Running migrations for blog:
 - Migrating forwards to 0008_auto__add_field_user_test.
 > blog:0008_auto__add_field_user_test
 - Loading initial data for blog.
No fixtures found.

此時,我們的資料表就添加了一個 test 欄位。資料庫的欄位變成  usname= rsj217  password=111 [email protected] test='test'

刪除一個欄位

有增加就有刪除。現在我們刪除 剛才那個 test 欄位

修改 models

class User(models.Model):

    username = models.CharField(max_length=20, unique=True)
    password = models.CharField(max_length=40)
    email = models.EmailField(max_length=80, unique=True)

更改之後執行 


python manage.py schemamigration app_name --auto

操作和效果如下 

(pythonenv)[email protected]:~/project/python/vitrual/dblog$ python manage.py schemamigration blog --auto

 ? The field 'User.test' does not have a default specified, yet is NOT NULL.
 ? Since you are removing this field, you MUST specify a default
 ? value to use for existing rows. Would you like to:
 ?  1. Quit now, and add a default to the field in models.py
 ?  2. Specify a one-off value to use for existing columns now
 ?  3. Disable the backwards migration by raising an exception.
 ? Please select a choice: 2
 ? Please enter Python code for your one-off default value.
 ? The datetime module is available, so you can do e.g. datetime.date.today()

 >>> 'test'
 - Deleted field test on blog.User
Created 0009_auto__del_field_user_test.py. You can now apply this migration with: ./manage.py migrate blog

(pythonenv)[email protected]:~/project/python/vitrual/dblog$ python manage.py migrate blog
Running migrations for blog:
 - Migrating forwards to 0009_auto__del_field_user_test.
 > blog:0009_auto__del_field_user_test
 - Loading initial data for blog.
No fixtures found.
(pythonenv)[email protected]:~/project/python/vitrual/dblog$ 

這樣就刪除了剛才那個 test 欄位

修改欄位屬性

第三個操作是最懵懂,搞了很久才成功。例如 修改 models 的 username 屬性 刪除 unique = True,修改models 如下

class User(models.Model):

    username = models.CharField(max_length=20)
    password = models.CharField(max_length=40)
    email = models.EmailField(max_length=80, unique=True)

更改之後執行 


python manage.py schemamigration app_name --auto

顯示 

(pythonenv)[email protected]:~/project/python/vitrual/dblog$ python manage.py schemamigration blog --auto
 - Deleted unique constraint for ['username'] on blog.User
Created 0010_auto__del_unique_user_username.py. You can now apply this migration with: ./manage.py migrate blog

此時,如果直接 執行 
python manage.py migrate app_name

一般情況下沒問題,直接更改。有時候會出現錯誤  "Database is locked"  。此時,只需要關閉 命令列,重新開啟就可以了。重新開啟 執行 

python manage.py migrate app_name

通常,只要原資料庫存在記錄,更改資料庫結構之後,一定要保持現有的記錄也要適用更改後的結構,否則會報錯。

例如剛才把 欄位唯一刪除了,要是添加了兩個同名使用者名稱,再把欄位唯一增加回來,此時資料庫記錄就會存在兩條使用者名稱一樣的記錄,會報錯,只能更改為不同的。