用Django和South重命名应用程序

时间:2010-12-30 23:09:17

标签: django migration rename django-south

我正在将应用程序重命名为更合适的名称。在这样做时,我想确保South正确迁移数据库(重命名数据库表并更改django_content_type或south_migrationhistory中的引用)。我知道如何migrate a model to a different app,但是当我尝试重命名应用程序本身时,South无法正确识别迁移历史记录。

不受欢迎的解决方案:在将old_app重命名为new_app时,我可以保留old_app/migrations,并将新迁移添加到此目录以将数据库迁移到引用{{ 1}}。

如果可能,我宁愿完全删除目录new_app。我还没有想过更好地解决这个问题。

使用Django South重命名应用程序而不丢失数据的最佳方法是什么?

6 个答案:

答案 0 :(得分:43)

我同意Laksham你应该避免这种情况。但有时,我们必须这样做。我过去曾遇到过这种情况而且我已经这样管理过了。

如果您想避免丢失数据,可以将旧的应用程序数据转储到json文件中。

python manage.py dumpdata old_app --natural --indent=4 1> old_app.json

请注意--natural选项将强制使用其自然键(app_name,model)导出内容类型

然后你可以创建一个小命令来打开这个json文件,并用new_app替换所有old_app引用。

这样的事情应该有效

class Command(BaseCommand):
    help = u"Rename app in json dump"

    def handle(self, *args, **options):
        try:
            old_app = args[0]
            new_app = args[1]
            filename = args[2]
        except IndexError:
            print u'usage :', __name__.split('.')[-1], 'old_app new_app dumpfile.json'
            return

        try:
            dump_file = open(filename, 'r')
        except IOError:
            print filename, u"doesn't exist"
            return

        objects = json.loads(dump_file.read())
        dump_file.close()

        for obj in objects:
            obj["model"] = obj["model"].replace(old_app, new_app, 1)

            if obj["fields"].has_key("content_type") and (old_app == obj["fields"]["content_type"][0]):
                obj["fields"]["content_type"][0] = new_app

        dump_file = open(filename, 'w')
        dump_file.write(json.dumps(objects, indent=4))
        dump_file.close()

然后重命名应用程序,在INSTALLED_APPS中更改名称。

然后,您应该删除所有南方迁移,重新生成并为新应用程序应用初始迁移。然后运行SQL命令:

update django_content_type set app_label='new_app' where app_label='old_app'

然后为新应用启动南迁移,以便创建表并加载json文件。

python manage.py loaddata old_app.json

我在项目上做了类似的事情,似乎工作正常。

我希望它有所帮助

答案 1 :(得分:24)

可以重命名应用。 作为示例项目,请参阅:

https://github.com/ASKBOT/django-south-app-rename-example

基本上,有2次迁移。首先使用db.rename_table()重命名表,然后更新内容类型。 通过检查if not db.dry_run:,可以将其合并为一个迁移。有关此示例,请参阅How do I migrate a model out of one django app and into a new one?

对于初始迁移,您可以直接重命名现有表,如果它们在那里:

if 'old_app_table_name' in connection.introspection.table_names():
    db.rename_table('old_app_table_name', 'new_app_table_name')
else:
    # Create new app tables directly.

对于具有更多迁移的表,您可能需要检查是否已应用旧迁移名称:

from south.models import MigrationHistory
if MigrationHistory.objects.exists(app_name='old_app', migration='0001_initial'):
    return

最后,我建议使用IDE(例如PyCharm试用版)重命名包(右键单击,重构 - >重命名包),因为它会更新整个应用程序的所有用法,包括URLconf,设置和进口。

答案 2 :(得分:8)

经过一番安慰,我想出了这个。应该好好照顾它。 https://gist.github.com/jamesmfriedman/6168003

答案 3 :(得分:2)

免责声明:这可能不是理想的实现方式,但绝对比其他地方/早期建议的许多其他方法容易。

如果您使用的是PyCharm,则可以尝试以下解决方案。

  • 右键单击Django项目中的应用目录
  • Refactor> Rename>输入新的应用名称(new_app
  • 同时检查Search for referencesSearch in comments and strings,范围Project Files> Refactor
  • 这将向您显示文件重命名的位置> Refactor
  • 如果您对项目名称不满意,也可以对项目名称进行同样的操作

现在是问题所在。

python manage.py makemigrations

python manage.py migrate

这会做什么?

  • 这基本上将创建一个新应用并将所有迁移应用到该新应用
  • 但是,您的数据仍驻留在旧应用(old_app
  • 我们需要将其带到new_app表中

在您的数据库中,我们需要

  1. 通过从new_app表中复制数据来将数据插入old_app表中

INSERT INTO new_app_table_name SELECT * FROM old_app_table_name;

您必须对应用中的所有模型/表格执行此操作

  1. 重置表的顺序,以避免在Django中出现主键冲突错误

SELECT setval('new_app_table_name_id_seq', (SELECT MAX(id) FROM new_app_table_name));

您必须对步骤1中的所有表执行此操作。

我不想变得无知,并声称它应该像这样简单。我的项目和模型结构相当复杂,但这对我来说就像是魅​​力。但是,如果您的项目结构过于复杂,那么其中只有部分内容可能对您有用。

计算机科学中只有两件事:缓存失效和命名。

-菲尔·卡尔顿

答案 4 :(得分:1)

免责声明:此答案适用于那些不关心迁移历史并且已经通过重命名应用程序搞砸了,完全忘记迁移的人(就像我一样)。 为我工作。

更改文件夹名称,处理代码中的所有导入并更改settings.INSTALLED_APPS中的相应应用程序名称后,只需删除所有以前的迁移文件夹。然后像这样做一个初始的

manage.py schemamigration new_app --initial

然后,在应用它时,假装它就像这样

manage.py migrate new_app 0001 --fake

不要忘了 - 假它,否则你可能会丢失数据

所有进一步的迁移都可以正常使用

manage.py migrate new_app 0002

您也可以从south_migrationhistory中删除app_name =“old_app”

答案 5 :(得分:-6)

我不会乱用应用程序名称。你可以随处参考应用名称。 URL confs,设置,其他应用,模板等。

django的设计方式,相应的南方,假设不需要更改应用程序名称。 - 为您的项目命名您想要的。你没有在任何地方引用它。更改应用程序名称非常麻烦。如果您真的想重命名您的应用,那么您不受欢迎的解决方案是我看到的最佳解决方案。

如果您愿意,可以使用python import as以不同的名称导入应用程序。