此时,使用 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
通常,只要原数据库存在记录,更改数据库结构之后,一定要保持现有的记录也要适用更改后的结构,否则会报错。
例如刚才把 字段唯一删除了,要是添加了两个同名用户名,再把字段唯一增加回来,此时数据库记录就会存在两条用户名一样的记录,会报错,只能更改为不同的。