在 Django 中更改数据库表

Posted

技术标签:

【中文标题】在 Django 中更改数据库表【英文标题】:Altering database tables in Django 【发布时间】:2010-09-07 08:26:02 【问题描述】:

我正在考虑将 Django 用于我正在启动的项目(仅供参考,一个基于浏览器的游戏),我最喜欢的功能之一是使用 syncdb 自动创建基于我定义的 Django 模型(我似乎在任何其他框架中都找不到的功能)。 当我在documentation 看到这个时,我已经在想这太好了,难以置信:

Syncdb 不会改变现有的表

syncdb 只会为尚未安装的模型创建表。它永远不会发出 ALTER TABLE 语句来匹配安装后对模型类所做的更改。对模型类和数据库模式的更改通常涉及某种形式的歧义,在这些情况下,Django 必须猜测要做出的正确更改。在此过程中存在丢失关键数据的风险。

如果您对模型进行了更改并希望更改数据库表以匹配,请使用 sql 命令显示新的 SQL 结构并将其与现有表架构进行比较以计算出更改。

似乎必须“手动”更改现有表。

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

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

有什么想法吗?

【问题讨论】:

【参考方案1】:

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

编辑:嘿,dmigrations 来了。

更新:由于最初编写此答案,django-evolution 和 dmigrations 都已停止积极开发,South 已成为 Django 中架构迁移的事实标准。 South 的部分内容甚至可能会在下一或两个版本中集成到 Django 中。

更新:Django 1.7+ 中包含一个基于 South(由 South 的作者 Andrew Godwin 编写)的架构迁移框架。

【讨论】:

django-evolution 似乎运行良好,谢谢!值得指出的是,必须从一开始就开始使用它(它不计算现有 SQL 的必要更改)。【参考方案2】:

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

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

【讨论】:

【参考方案3】:

实现此目的的一个好方法是通过夹具,尤其是 initial_data 夹具。

fixture 是包含数据库序列化内容的文件集合。因此,这就像对数据库进行备份,但 Django 知道它更易于使用,并且在您进行单元测试之类的事情时会有额外的好处。

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

您可以使用django-admin.py loaddata 加载fixture,但更重要的是,如果您的fixture 的名称类似于initial_data.json,它会在您执行syncdb 时自动加载,省去了自己导入的麻烦。

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

当然,当您将属性添加到模型和列到数据库时,这将起作用。如果您从数据库中删除一列,则需要更新您的固定装置以删除该列的数据,这可能并不简单。

这在开发过程中进行大量小的数据库更改时效果最佳。对于更新生产数据库,手动生成的 SQL 脚本通常效果最好。

【讨论】:

【参考方案4】:

我一直在使用 django-evolution。警告包括:

它的自动建议一律烂掉;和 它的指纹函数在不同平台上为同一个数据库返回不同的值。

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

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-evolution 对我来说效果很好。有时我必须添加一个我不想在模型中指定的默认值(而是告诉 django-evolution 只为现有字段设置它),但除此之外 - 没有抱怨。【参考方案5】:

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

【讨论】:

【参考方案6】:

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

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

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

【讨论】:

【参考方案7】:

Django 1.7(目前正在开发中)是 adding native support,用于架构迁移,带有 manage.py migratemanage.py makemigrationsmigrate 已弃用 syncdb)。

【讨论】:

以上是关于在 Django 中更改数据库表的主要内容,如果未能解决你的问题,请参考以下文章

在不删除表的情况下更改模型中的 Django 数据类型

更改应用程序名称和数据库表后 Django 无法进行迁移

django Models与数据库关系

运行显式创建表的迁移时未创建 Django 表。

django使用models创建表

Heroku 和 Django 组合中的 Postgresql 更改与共享数据库