【问题标题】:How to load fixtures in Django south migrations properly?如何正确加载 Django 南迁移中的固定装置?
【发布时间】:2012-11-29 07:10:09
【问题描述】:

我正在使用 Django 1.5b1 和南迁移,生活总体上很好。我有一些架构更新来创建我的数据库,其中包括一个用户表。然后我为ff.User(我的自定义用户模型)加载一个夹具:

def forwards(self, orm):
        from django.core.management import call_command
        fixture_path = "/absolute/path/to/my/fixture/load_initial_users.json"
        call_command("loaddata", fixture_path)

在我将另一个字段添加到我的 ff.User 模型之前,一切都运行良好,在迁移线的更下方。我的夹具负载现在中断:

DatabaseError: Problem installing fixture 'C:\<redacted>create_users.json':
Could not load ff.User(pk=1): (1054, "Unknown column 'timezone_id' in 'field list'")

时区是我添加到我的用户模型中的字段 (ForeignKey)。

ff.User 与数据库中的不同,因此 Django ORM 放弃了数据库错误。不幸的是,我无法在我的夹具中将我的模型指定为orm['ff.User'],这似乎是南方的做事方式。

我应该如何使用 south 正确加载固定装置,以便在修改这些固定装置所针对的模型后它们不会损坏?

【问题讨论】:

  • 能否向我们展示您的迁移代码?

标签: django django-south


【解决方案1】:

我找到了一个可以完成这项工作的 Django sn-p!

https://djangosnippets.org/snippets/2897/

它根据固定在夹具中的模型而不是应用程序代码中的实际模型定义来加载数据!非常适合我。

【讨论】:

    【解决方案2】:

    我提出了一个你可能也会感兴趣的解决方案:

    https://stackoverflow.com/a/21631815/797941

    基本上,这就是我加载我的夹具的方式:

    from south.v2 import DataMigration
    import json
    
    class Migration(DataMigration):
    
        def forwards(self, orm):
            json_data=open("path/to/your/fixture.json")
            items = json.load(json_data)
            for item in items:
                # Be carefull, this lazy line won't resolve foreign keys
                obj = orm[item["model"]](**item["fields"])
                obj.save()
    
            json_data.close()
    

    【讨论】:

      【解决方案3】:

      这对我来说也是使用固定装置的一个令人沮丧的部分。我的解决方案是制作一些辅助工具。一种通过从数据库中采样数据来创建夹具并在夹具中包含南迁移历史的方法。

      还有一个工具可以将南迁移历史添加到现有的装置中。

      第三个工具在修改此夹具时检查提交,加载夹具,然后检查最近的提交并进行南迁移并将迁移的数据库转储回夹具。这是在单独的数据库中完成的,因此您的默认数据库不会被踩到。

      前两个可以视为测试代码,第三个请视为可用的 alpha,但它们已经对我很有帮助。

      希望从其他人那里得到一些反馈: git@github.com:JivanAmara/django_fixture_tools.git 目前只支持使用 git 作为 RCS 的项目。

      【讨论】:

        【解决方案4】:

        我找到的最优雅的解决方案是here,您的应用模型的get_model 函数被切换为从提供的orm 提供模型。然后在应用夹具后将其设置回来。

        from django.db import models
        from django.core.management import call_command
        
        def load_fixture(file_name, orm):
            original_get_model = models.get_model
        
            def get_model_southern_style(*args):
                try:
                    return orm['.'.join(args)]
                except:
                    return original_get_model(*args)
        
            models.get_model = get_model_southern_style
            call_command('loaddata', file_name)
            models.get_model = original_get_model
        

        您在转发定义中使用load_fixture('my_fixture.json', orm) 调用它。

        【讨论】:

        【解决方案5】:

        通常 South 使用 forwards()backwards() 函数处理迁移。在您的情况下,您应该:

        • 更改夹具以包含正确的数据,或
        • 在破坏它的迁移之前导入固定装置(或在同一迁移中,但在改变架构之前),

        在第二种情况下,在迁移添加(或在您的情况下,删除)列之前,您应该执行将显式加载固定装置的迁移(docs):

        def forwards(self, orm):
            from django.core.management import call_command
            call_command("loaddata", "create_users.json")
        

        我相信这是完成您需要的最简单的方法。还要确保在应用旧迁移之前不要犯一些简单的错误,例如尝试使用新结构导入数据。

        【讨论】:

        • 我使用您描述的加载夹具的确切方法。不幸的是,它违反了south 在迁移中不使用显式模型的规则。 Fixtures 使用显式的app.Model 而不是冻结的orm['app.Model'],这是我的问题的根源。我不建议任何人在南迁中使用固定装置,因为它必然会导致问题。请参阅我的答案,了解我如何使用替代方法解决此问题。
        【解决方案6】:

        阅读以下两篇文章帮助我想出了一个解决方案:

        http://andrewingram.net/2012/dec/common-pitfalls-django-south/#be-careful-with-fixtures

        http://news.ycombinator.com/item?id=4872596

        具体来说,我重写了我的数据迁移以使用来自 'dumpscript' 的输出

        我需要对生成的脚本稍作修改才能与 south 一起使用。而不是做

        from ff.models import User
        

        我愿意

        User = orm['ff.User']
        

        这完全符合我的要求。此外,它的好处是不需要像固定装置那样硬编码 ID。

        【讨论】:

        • 你能告诉我们content of the migration script吗?这将有助于其他人了解您面临的问题,以便他们可以解决类似的问题。目前,该问题可能不够清楚,无法对有类似问题的人有所帮助。
        猜你喜欢
        • 2011-04-29
        • 1970-01-01
        • 2011-05-03
        • 2014-06-22
        • 1970-01-01
        • 2014-12-21
        • 2011-04-03
        • 1970-01-01
        相关资源
        最近更新 更多