django的数据库迁移
>>python manage.py syncdb
但是django也不会如你预期去按照代码更新数据库中的表结构。
Syncdb will not alter existing tables syncdb will only create tables for models which have not yet been installed. It will never issue ALTER TABLE statements to match changes made to a model class after installation. Changes to model classes and database schemas often involve some form of ambiguity and, in those cases, Django would have to guess at the correct changes to make. There is a risk that critical data would be lost in the process.
大体意思就是当models从来没有进入数据库时,syncdb才会创建一个新的数据库,而永远都不会改变已经进入数据库的models。所以虽然使用:
>>python manage.py sql MyApp
看到的数据模型跟自己在代码中写的完全一样,但是一旦执行对象的save函数,由于数据库中并没有真正更新成代码中的数据模型,就会出现找不到数据列的错误;
DatabaseError: table MyModels has no column named NewAddVar
为了解决这个问题,可以先进入数据库添加、删除表项,但是这样太麻烦了。还有个方法就是用South做数据迁移。下面就简单说一下怎么在代码中Models变更后,用South改变数据库的结构。
首先,安装一下python的包安装工具pip:
>>sudo apt-get install python-pip
然后,用pip安装South,当然也可以手工安装,这里用pip可以省事点:
>>sudo pip install South
这里要用sudo,以免安装时出现目录不能写的问题。
安装south后,要修改一下django的配置文件settings.py,把south加到INSTALLED_APPS中。
接下来,执行:
>>python manage.py syncdb
运行结果显示,除了创建各种app的数据库,还创建了一个south的迁移数据库:
Creating table south_migrationhistory
搞定了south迁移数据库的创建,接下来要用south对每个app做备份和迁移准备:
>>python manage.py schemamigration MyApp --initial
这样就在应用下创建了迁移数据。我的理解是south代替sycndb接管了MyApp的models的数据库,所以这时候再执行:
>>python manage.py syncdb
会显示:
Not synced (use migrations):
- project.MyApp
当要更改数据模型时,还要执行一下:
>>python manage.py migrate MyApp 0001 --fake”
south不会真正开始迁移数据,但是会在自己的表中记录下变化,便于后续的迁移。
最后,修改自己的Models,并且迁移数据:
>>python manage.py schemamigration MyApp --auto
>>python manage.py migrate MyApp
ps:在执行这个过程中,我还碰到过数据没有默认值的问题,在运行:
>>python manage.py schemamigration MyApp --auto
会出现这些提示:
The field 'MyApp.name' does not have a default specified, yet is NOT NULL.
? Since you are making this field nullable, you MUST specify a default
? value to use for existing rows. Would you like to:
? 1. Quit now.
? 2. Specify a one-off value to use for existing columns now
? 3. Disable the backwards migration by raising an exception; you can edit the migration to fix it later
? Please select a choice:
我是直接选2,指定了一个,但是我感觉这个有点问题,有些值本来就是空的,为什么非要指定一个默认值呢?但是后来这个问题没有重现了,所以就先搁置了。