在本文中, 将会介绍Django-south的基本概念和基本用法, 帮助Django开发人员简化数据迁移的过程. 在django-admin命令中有syncdb指令, 其目的是根据model.py创建相应的数据库表. 但我们在开发的过程中, 经常会需要更改model, 删除或者增加Field, 这时, syncsb命令就不那么好用了, 因为syncsb无法自动更改数据库表结构. 因此, 我们时常需要手动删除数据库表, 再运行syncdb.
而有了south后, 情况就不同了. south为django带来了数据迁移功能, 它的主要目的是为django应用程序带来一个简单, 稳定, 与数据库管理系统无关的迁移层, 用来自动处理django中的数据表变化. 使用south提提供的工具, 你可以在不同版本的数据库结构中来回迁移,
south刚出来时只是一个相对无名的数据库迁移应用. 但渐渐地它成为了django中最为流行和普遍使用的数据迁移工具. 并且在django 1.7发布时, 数据迁移功能将会被整合到django中, 其提供的django-admin migrate也将代替syncdb命令. 因此, 我们不得不了解一下south的魅力所在.
安装south的方式有许多中, 包括从pip安装, 直接使用south的Mercurial库安装, 或从操作系统自带的软件库中安装. 推荐使用pip, 将south安装到VirtualEnv中:
pip install South
然后在django的'south'添加到setting.py的INSTALLED_APPS中, 并运行syncdb, 创建south所需要的数据表:
./manage.py syncdb
首先我们介绍在新app中使用south. 需要注意的是, south的迁移记录文件是储存在每个app下的migrations目录中的, 如果该app没有创建任何migrations, 那么该app还是通过syncdb来管理的.
创建新app, 并将其添加到INSTALLED_APPS中:
./manage.py startapp southtut
打开该app的model.py, 创建model:
from django.db import modelsclass Knight(models.Model): name = models.CharField(max_length=100) of_the_round_table = models.BooleanField()
south提供了多种建立迁移记录的方式, 有些是自动的, 有些是手动的. 而用的最多的可能就是--auto和--initial这两种自动创建的方式了.
--auto是根据之前的迁移记录, 与当前model作比较, 然后自动创建新的迁移记录. 例如当添加了一个新field时, --auto会注意到, 并自动生成添加了新栏的迁移记录.
你会注意到, --auto需要上一次的迁移记录才能创建新的迁移记录. 而--initial则可以用来为model中所有的表创建初始的迁移记录. 因此, 先使用--initial初始化迁移记录, 然后在model有所变动后, 使用--auto自动生成迁移记录
使用--initial为我们新建的app southtut创建初始迁移记录:
$ ./manage.py schemamigration southtut --initialCreating migrations directory at '/home/andrew/Programs/litret/southtut/migrations'...Creating __init__.py in '/home/andrew/Programs/litret/southtut/migrations'... + Added model southtut.KnightCreated 0001_initial.py. You can now apply this migration with: ./manage.py migrate southtut
此时, 在southtut的migrations下就自动生成reated 0001_initial.py文件, 这就是第一个迁移记录文件. 注意, 此时打开MySQL或PostreSQL, 你会发现没有名为southtut_knight的数据表, 因为数据库中的数据表并没有变化(未创建也未修改), 我们需要用到migrate命令来完成这一步:
$ ./manage.py migrate southtutRunning migrations for southtut:- Migrating forwards to 0001_initial.> southtut:0001_initial- Loading initial data for southtut.
此时再打开MySQL或PostgreSQL, southtut_knight数据表已经创建好了. 但到现在为止, 这些功能都是sync能实现的. 接下来我们修改Knight model, 增加一个field:
from django.db import modelsclass Knight(models.Model): name = models.CharField(max_length=100) of_the_round_table = models.BooleanField() dances_whenever_able = models.BooleanField()
此时如果使用syncsb, 则django无法为你增加dances_whenever_able列, 因此, 我们使用south:
$ ./manage.py schemamigration southtut --auto+ Added field dances_whenever_able on southtut.KnightCreated 0002_auto__add_field_knight_dances_whenever_able.py. You can now apply this migration with: ./manage.py migrate southtut
从输出的提示可以看到, south已经为你增加了新的迁移记录文件(0002_auto__add_field_knight_dances_whenever_able.py), south的命名方式是序列号+所做的更改. 接下来, 我们根据提示, 使用migrate命令修改数据库:
$ ./manage.py migrate southtutRunning migrations for southtut:- Migrating forwards to 0002_auto__add_field_knight_dances_whenever_able.> southtut:0002_auto__add_field_knight_dances_whenever_able- Loading initial data for southtut.
当修改model时, 创建没有默认值(default)的field后:
from django.db import modelsclass Knight(models.Model): name = models.CharField(max_length=100) of_the_round_table = models.BooleanField() dances_whenever_able = models.BooleanField() shrubberies = models.IntegerField(null=False)
此时再执行schemamigration, 会出现一些没有见过的选择:
./manage.py schemamigration southtut --auto ? The field 'Knight.shrubberies' does not have a default specified, yet is NOT NULL. ? Since you are adding or 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 ? Please select a choice:
其中选项1意思是, 放弃本次自动迁移, 并退出, 你可以在field中添加default值后再执行schemamigration. 选项2的意思是, 为已经存在的行添加一个一次性的值. 当你选择2时, 会出现python提示行, 你可以使用python的datetime模块:
? 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() >>> 0 + Added field shrubberies on southtut.KnightCreated 0003_auto__add_field_knight_shrubberies.py. You can now apply this migration with: ./manage.py migrate southtut
此时你可以查看自动生成的迁移记录文件, south会为新建的栏添加默认值0, 这样数据库才不会报错. 然后我们再执行migrate:
$ ./manage.py migrate southtut Running migrations for southtut: - Migrating forwards to 0003_auto__add_field_knight_shrubberies. > southtut:0003_auto__add_field_knight_shrubberies - Loading initial data for southtut.mou