django 数据库增强工具 south 的安装使用和注意事项。。。

时间:2021-02-07 15:04:52
django 开发 web 应用的时候,其中的 ORM 非常好用。 通过 moldes 的定义和调用。可是,django 在 数据库同步 (syncdb) 的时候。只会创建不存在的数据表。对于中途需要修改 model ,比如增加字段,删除字段,修改字段等操作  syncdb是 不会对数据库有任何更改。

此时,使用 south 可以达到 修改 models 的时候, 自动更改数据库表结构。

south的安装

​安装 south 很简单

pip install south

添加 south 到项目中

对于 添加 south 到项目中,主要有三种情况。参考 * 上的总结 如下:


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=rsj217@gmail.com  会出现下面这个 

(pythonenv)ghost@ghost-H61M-S2V-B3:~/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)ghost@ghost-H61M-S2V-B3:~/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)ghost@ghost-H61M-S2V-B3:~/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)ghost@ghost-H61M-S2V-B3:~/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=rsj217@gmail.com 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)ghost@ghost-H61M-S2V-B3:~/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.UserCreated 0009_auto__del_field_user_test.py. You can now apply this migration with: ./manage.py migrate blog
(pythonenv)ghost@ghost-H61M-S2V-B3:~/project/python/vitrual/dblog$ python manage.py migrate blogRunning 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)ghost@ghost-H61M-S2V-B3:~/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)ghost@ghost-H61M-S2V-B3:~/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

通常,只要原数据库存在记录,更改数据库结构之后,一定要保持现有的记录也要适用更改后的结构,否则会报错。

例如刚才把 字段唯一删除了,要是添加了两个同名用户名,再把字段唯一增加回来,此时数据库记录就会存在两条用户名一样的记录,会报错,只能更改为不同的。