部分参考自: http://blog.csdn.net/kingmari/article/details/7908153
in-memery structure计算models和当前migration文件的整体状态计算出差异,生成新的migration文件。
from django.db import migrations, models class Migration(migrations.Migration): dependencies = [("migrations", "0001_initial")] operations = [ migrations.DeleteModel("Tribble"), migrations.AddField("Author", "rating", models.IntegerField(default=0)), ]
$ python manage.py makemigrations your_app_label
之后会产生当前app的一个新的初始migration文件。
$ python manage.py migrate --fake-initial
Django 将会确认你已经有一个初始migration文件并且数据表已经存在,并且标记生成的migration文件已经执行过了。
这能正常工作需要2个条件:
这种情况下Django会提醒你并给出相应操作,如果Django认为无影响,会依次执行执行migration里的修改,否则需要修改migration文件。
个人意见:
最好时刻保持database和model一致,开发者之间常沟通,下面提到的数据迁移最好用导出sql脚本的方式,数据迁移写着麻烦,也容易出错。
变更数据的迁移被称为“data migrations”;它们最好写成单独的脚本,放在你的架构迁移脚本旁边。
django不会自动为你创建数据迁移脚本,它只会生成架构迁移,但是写这些数据迁移也不是很难。django中的迁移脚本由 Operations组成,数据迁移的主要操作是RunPython。
开始时,生成一个空的迁移脚本(django会放置文件在正确的地方,建议一个文件名称,并添加依赖):
$ python manage.py makemigrations --empty yourappname
然后,打开文文件:
from django.db import models, migrations class Migration(migrations.Migration): dependencies = [ ('yourappname', '0001_initial'), ] operations = [ ]
现在,你所需要做的就是创建一个新的函数让RunPython调用。
文档示例:
from django.db import models, migrations def combine_names(apps, schema_editor): Person = apps.get_model("yourappname", "Person") for person in Person.objects.all(): person.name = "%s %s" % (person.first_name, person.last_name) person.save() class Migration(migrations.Migration): dependencies = [ ('yourappname', '0001_initial'), ] operations = [ migrations.RunPython(combine_names), ]
一旦完成了脚本,我们能正常运行python manage.py migrate,数据迁移会和其他迁移一同完成。
Django通过收集所有现存的迁移脚本,抽出它们的操作,然后把它们放到一个序列中,对它们进行一个优化来减少序列的长度 - 例如,它知道CreateModel 和 DeleteModel 操作相互抵消,它也知道AddField可以整合到CreateModel中。
一旦操作序列被尽可能的减少 - 这个数量可能取决于你的模型相互缠结的程度和是否有RunSQL 或 RunPython 操作 (这些都不能被优化) - Django将把它们写回到一套新的初始化迁移脚本中。
这些脚本被标记为取代之前的脚本 - 合并脚本,所以它们能够和旧的脚本共存,Django能智能的在它们之中切换。如果你还处于合并迁移过程中,它会继续使用原来的脚本直到合并脚本的最后一项,然后切换到合并历史版本,这样新安装时会只使用新的合并脚本而跳过所有老的脚本。
这保证了你能进行合并而不会弄乱并非完全保持最新的生产系统。推荐流程是进行合并,保留老的脚本,提交和发布,等待所有系统都升级到新的版本(或者如果是第三方工程,保证你的用户顺序升级而不要跳过任何一步),然后删除老的文件,提交和进行下个版本开发。
命令是squashmigrations:
$ ./manage.py squashmigrations myapp 0004
注意模型依赖在Django中可能会非常复杂,合并可能导致优化后的迁移不能功能或不能运行。这种情况下,你可以使用--no-optimize,不过请报告一个bug( file a bug report),告知模型细节和它们的关系,这样我们可以针对它改善优化器。
一旦你合并了你的迁移,你应该和原迁移一起提交并发布变更到所有的你的运行中的应用上,确保它们运行migrate并将变更保存到数据库中。
完成之后,你需要将合并迁移脚本转换成一个普通的初始化迁移脚本,通过:
注意:
一旦你合并了迁移,你不能重复合并直到你把它完全转换成一个普通的脚本。
Django的数据库层从Python代码生成SQL schemas—但是对于遗留数据库,你已经拥有SQL schemas。这种情况,你需要为已经存在的数据表创建model。为此,Django自带了一个可以通过读取您的数据表结构来生成model的工具。该辅助工具称为inspectdb,你可以通过执行manage.py inspectdb来调用它。
这种操作很渣,你需要对产生的模型代码做一些清理:
数据库的每一个表都会被转化为一个model类 (也就是说,数据库的表和model 的类之间做一对一的映射)。 这意味着你需要为多对多连接的表,重构其models 为 ManyToManyField 的对象。
每一个字段类型,如CharField、DateField, 是通过查找数据库列类型如VARCHAR,DATE来确定的。 如果inspectdb无法对某个model字段类型根据数据库列类型进行映射,那么它会使用TextField字段进行代替,并且会在所生成model 字段后面加入Python注释“该字段类型是猜的”。
数据库中某个列的名字是Python的保留字,比如pass、class或者for等,inspectdb会在每个属性名后附加上 field,并将db column属性设置为真实的字段名,比如pass,class或者for等。
库中某张表引用了其他表(正如大多数数据库系统所做的那样),你需要适当的修改所生成model的顺序,以使得这种引用能够正确映射。 例如,model Book拥有一个针对于model Author的外键,那么后者应该先于前者被定义。
PostgreSQL,MySQL和SQLite数据库系统,inspectdb能够自动检测出主键关系。 也就是说,它会在合适的位置插入primary key=True。 而对于其他数据库系统,你必须为每一个model中至少一个字段插入这样的语句,因为Django的model要求必须拥有一个 primary key=True的字段。
检测仅对PostgreSQL,还有MySQL表中的某些特定类型生效。 至于其他数据库,外键字段都将在假定其为INT列的情况下被自动生成为IntegerField。