繁体   English   中英

Django:迁移错误中的loaddata

[英]Django: loaddata in migrations errors

自从使用Django迁移(不是南方)并在其中使用loaddata for fixture以来,我发生了一些令人讨厌的事情。

这是一个重现我的问题的简单方法:

  • 使用1字段field1 (CharField或其他)创建一个新模型Testmodel
  • 使用makemigrations创建关联的迁移(假设为0001
  • 运行迁移
  • 并在新表中添加一些数据
  • 将数据转储到fixture testmodel.json
  • 使用call_command('loaddata', 'testmodel.json')创建迁移:迁移0002
  • 在模型中添加一些新字段: field2
  • 创建关联的迁移( 0003

现在,提交,并将您的数据库置于更改之前的状态: ./manage.py migrate myapp zero 所以你和你的队友处于同样的状态,但还没有得到你的改变。

如果您再次尝试运行./manage.py migrate ,则会在迁移0002时收到ProgrammingError ,说“column field2不存在”。

这似乎是因为loaddata正在查看你的模型(已经有了field2 ),而不仅仅是将数据包应用到db。

在团队中工作时,可能会发生多种情况,也会导致测试运行器失败。

我弄错了吗? 这是一个错误吗? 应该做些什么呢?

-

我正在使用django 1.7

loaddata命令只会调用序列化程序。 序列化程序将处理models.py文件中的模型状态,而不是当前迁移,但是没有什么可以欺骗默认的序列化程序。

首先,您不希望通过call_command使用该序列化call_command ,而是直接使用该序列化call_command

from django.core import serializers

def load_fixture(apps, schema_editor):
    fixture_file = '/full/path/to/testmodel.json'
    fixture = open(fixture_file)
    objects = serializers.deserialize('json', fixture, ignorenonexistent=True)
    for obj in objects:
        obj.save()
    fixture.close()

其次,序列化器使用的monkey-patch apps注册表:

from django.core import serializers

def load_fixture(apps, schema_editor):
    original_apps = serializers.python.apps
    serializers.python.apps = apps
    fixture_file = '/full/path/to/testmodel.json'
    fixture = open(fixture_file)
    objects = serializers.deserialize('json', fixture, ignorenonexistent=True)
    for obj in objects:
        obj.save()
    fixture.close()
    serializers.python.apps = original_apps

现在,序列化程序将使用apps模型状态而不是默认状态,整个迁移过程将成功。

当你运行python manage.py migrate它试图在fixtures文件夹中加载你的testmodel.json ,但你的模型(更新后)与testmodel.json数据不匹配。 你可以试试这个:

  • 将目录从fixture更改为_fixture

  • 运行python manage.py migrate

  • 可选,您现在可以通过fixture更改_fixture并像以前一样使用python manage.py loaddata app/_fixtures/testmodel.json加载数据来使用migrate命令或加载数据

扩展GwynBleidD的答案并混合使用此问题,因为Postgres在以这种方式加载时不会重置主键序列( https://stackoverflow.com/a/14589706/401636

我想我现在有一个用于加载夹具数据的故障安全迁移。

utils.py:

import os

from io import StringIO

import django.apps

from django.conf import settings
from django.core import serializers
from django.core.management import call_command
from django.db import connection


os.environ['DJANGO_COLORS'] = 'nocolor'


def reset_sqlsequence(apps=None, schema_editor=None):
    """Suitable for use in migrations.RunPython"""

    commands = StringIO()
    cursor = connection.cursor()
    patched = False

    if apps:
        # Monkey patch django.apps
        original_apps = django.apps.apps
        django.apps.apps = apps
        patched = True
    else:
        # If not in a migration, use the normal apps registry
        apps = django.apps.apps

    for app in apps.get_app_configs():
        # Generate the sequence reset queries
        label = app.label
        if patched and app.models_module is None:
            # Defeat strange test in the mangement command
            app.models_module = True
        call_command('sqlsequencereset', label, stdout=commands)
        if patched and app.models_module is True:
            app.models_module = None

    if patched:
        # Cleanup monkey patch
        django.apps.apps = original_apps

    sql = commands.getvalue()
    print(sql)
    if sql:
        # avoid DB error if sql is empty
        cursor.execute(commands.getvalue())


class LoadFixtureData(object):
    def __init__(self, *files):
        self.files = files

    def __call__(self, apps=None, schema_editor=None):
        if apps:
            # If in a migration Monkey patch the app registry
            original_apps = serializers.python.apps
            serializers.python.apps = apps

        for fixture_file in self.files:
            with open(fixture_file) as fixture:
                objects = serializers.deserialize('json', fixture)

                for obj in objects:
                    obj.save()

        if apps:
            # Cleanup monkey patch
            serializers.python.apps = original_apps

现在我的数据迁移看起来像:

# -*- coding: utf-8 -*-
# Generated by Django 1.11.1 on foo
from __future__ import unicode_literals

import os

from django.conf import settings
from django.db import migrations

from .utils import LoadFixtureData, reset_sqlsequence


class Migration(migrations.Migration):

    dependencies = [
        ('app_name', '0002_auto_foo'),
    ]

    operations = [
        migrations.RunPython(
            code=LoadFixtureData(*[
                os.path.join(settings.BASE_DIR, 'app_name', 'fixtures', fixture) + ".json"
                for fixture in ('fixture_one', 'fixture_two',)
            ]),
            # Reverse will NOT remove the fixture data
            reverse_code=migrations.RunPython.noop,
        ),
        migrations.RunPython(
            code=reset_sqlsequence,
            reverse_code=migrations.RunPython.noop,
        ),
    ]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM