改变Django中的数据库表

Altering database tables in Django

我正在考虑将Django用于我正在开始的项目(fyi,一个基于浏览器的游戏),我最喜欢的一个功能是使用syncdb自动创建基于Django模型的数据库表我 define(我似乎无法在任何其他框架中找到的功能)。
当我在文档中看到这个时,我一直认为这太好了,不可能是真的:

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.

If you have made changes to a model and wish to alter the database tables to match, use the sql command to display the new SQL structure and compare that to your existing table schema to work out the changes.

似乎改变现有的表必须"手动"完成。

我想知道的是最好的方法。 我想到了两种解决方案:

  • 如文档所示,在DB中手动进行更改;
  • 做一个数据库备份,擦除它,再次创建表(使用syncdb,因为它现在从头开始创建表)并导入备份数据(如果数据库很大,这可能需要很长时间)

有任何想法吗?


手动执行SQL更改和转储/重新加载都是选项,但您可能还想查看Django的一些架构演变包。最成熟的选择是django-evolution和South。

编辑:嘿,这里有dmigrations。

更新:由于这个答案最初编写,django-evolution和dmigrations都停止了积极的开发,而South已成为Django中模式迁移的事实标准。在下一个或两个版本中,南部的部分甚至可以集成到Django中。

更新:基于South的模式迁移框架(由South的作者Andrew Godwin撰写)包含在Django 1.7+中。


正如同一主题的其他答案所述,请务必在YouTube上观看DjangoCon 2008 Schema Evolution Panel。

此外,地图上还有两个新项目:Simplemigrations和Migratory。


一个很好的方法是通过灯具,特别是initial_data灯具。

fixture是包含数据库的序列化内容的文件集合。所以就像拥有数据库的备份一样,但是Django知道它更容易使用,并且当你来做单元测试时会有额外的好处。

您可以使用django-admin.py dumpdata从数据库中当前数据创建夹具。默认情况下,数据采用JSON格式,但也可以使用其他选项(如XML)。存储fixture的好地方是应用程序目录的fixtures子目录。

您可以使用django-admin.py loaddata加载修复,但更重要的是,如果您的夹具具有类似initial_data.json的名称,它将在您执行syncdb时自动加载,从而省去了自行导入它的麻烦。

另一个好处是,当您运行manage.py test运行单元测试时,临时测试数据库也将加载初始数据夹具。

当然,当您将模型和列的属性添加到数据库时,这将起作用。如果从数据库中删除列,则需要更新夹具以删除该列的数据,这可能不是直截了当的。

在开发期间进行大量的数据库更改时,这种方法效果最佳。对于更新生产数据库,手动生成的SQL脚本通常最有效。


我一直在使用django-evolution。注意事项包括:

  • 它的自动建议已经统一腐烂;和
  • 其指纹函数为不同平台上的同一数据库返回不同的值。

也就是说,我发现自定义schema_evolution.py方法很方便。要解决指纹问题,我建议代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
BEFORE = 'fv1:-436177719' # first fingerprint
BEFORE64 = 'fv1:-108578349625146375' # same, but on 64-bit Linux
AFTER = 'fv1:-2132605944'
AFTER64 = 'fv1:-3559032165562222486'

fingerprints = [
    BEFORE, AFTER,
    BEFORE64, AFTER64,
    ]

CHANGESQL ="""
    /* put your SQL code to make the changes here */
   """

evolutions = [
    ((BEFORE, AFTER), CHANGESQL),
    ((BEFORE64, AFTER64), CHANGESQL)
    ]

如果我有更多的指纹和变化,我会重新考虑它。在此之前,让它更清洁会从其他东西中窃取开发时间。

编辑:鉴于我正在手动构建我的更改,我将在下次尝试dmigrations。


django-command-extensions是一个django库,它为manage.py提供了一些额外的命令。其中一个是sqldiff,它应该为您提供更新到新模型所需的sql。然而,它被列为"非常实验性的"。


Django 1.7(目前正在开发中)使用manage.py migratemanage.py makemigrations(migrate弃用syncdb)为模式迁移添加本机支持。


到目前为止,在我的公司,我们使用了手动方法。最适合您的方法在很大程度上取决于您的开发风格。

我们通常在生产系统中没有那么多架构更改,并且从开发服务器到生产服务器的部署正式推出。每当我们推出(每年10-20次)时,我们会对当前和即将到来的生产分支进行填充,检查所有代码,并注意生产服务器上需要更改的内容。所需的更改可能是其他依赖项,对设置文件的更改以及对数据库的更改。

这对我们来说非常有效。让它全部自动化是一个利基愿景,但对我们来说很难 - 也许我们可以管理迁移,但我们仍然需要处理额外的库,服务器,无论依赖性。