【问题标题】:Django data migration raising a Type ErrorDjango 数据迁移引发类型错误
【发布时间】:2015-06-17 06:15:50
【问题描述】:

我有两个相关的模型; ItemCategory,我正在尝试编写数据迁移以将现有项目放入类别中。到目前为止,迁移看起来像这样:

def categorise(apps, schema_editor):
    Category = apps.get_model("orders", "Category")
    Item = apps.get_model("orders", "Item")
    some_category = Category.objects.create(name="Category name")
    some_category.items.add(Item.objects.get(name="Item name"))


class Migration(migrations.Migration):

    dependencies = [
        ('orders', '0005_populate'),
    ]

    operations = [
        migrations.RunPython(categorise)
    ]

模型的(相关部分)如下所示:

class Item(models.Model):
    name = models.CharField(max_length=200)

class Category(models.Model):
    name = models.CharField(max_length=200)
    items = models.ManyToManyField(Item)

但是,当我执行上面列出的迁移时,我在 categorise 函数的最后一行遇到了类型错误。它告诉我TypeError: 'Item' instance expected, got <Item: Item object>。这很奇怪,因为它们看起来像是同一类型。我注意通过应用程序而不是通过常规的 import 导入 Item 模型,以确保它与创建当前数据库中的项目的历史模型定义相同。

可能是什么原因?

编辑:以下是之前迁移的相关内容。我现在意识到其中一些起源于我更新到 Django 1.8 之前。这有关系吗?

编辑 2: 事实证明,直接连续运行两次 python manage.py migrate 确实可以解决问题。这是什么意思?

更新:这是 1.8 中的一个错误,但会在合并 ticket 24573 的补丁时修复。

0001:

class Migration(migrations.Migration):

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Item',
            fields=[
                ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
                ('name', models.CharField(max_length=200))
            ],
            options={
            },
            bases=(models.Model,),
        ),
    ]

0002:

class Migration(migrations.Migration):

    dependencies = [
        ('orders', '0001_initial'),
    ]

    operations = [
        migrations.CreateModel(
            name='Category',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=200)),
                ('items', models.ManyToManyField(to='orders.Item'))
            ],
            options={
            },
            bases=(models.Model,),
        ),
    ]

0003:

class Migration(migrations.Migration):

    dependencies = [
        ('orders', '0002_category'),
    ]

    operations = [
        migrations.AlterField(
            model_name='item',
            name='discounts',
            field=models.ManyToManyField(blank=True, to='orders.Discount'),
            preserve_default=True,
        ),
    ]

0005:

def populate(apps, schema_editor):
    Item = apps.get_model("orders", "Item")

    def add_item(name):
        item = Item.objects.create(name=name)
        # ..

    add_item("Item name", 160)
    # .. etc

class Migration(migrations.Migration):

    dependencies = [
        ('orders', '0004_auto_20150328_0929'),
    ]

    operations = [
        migrations.RunPython(populate)
    ]

【问题讨论】:

  • 我可以确认,截至 2021 年 2 月 17 日,这个问题在 django 2.2.15 中仍然存在。

标签: python django typeerror database-migration


【解决方案1】:

我的猜测是您使用的是 1.7。并且apps 中的模型在先前迁移的更改影响其中一个后未正确重新加载。在 1.8 中对此进行了更好的处理。

一种解决方法是直接使用添加Item的主键:

def categorise(apps, schema_editor):
    Category = apps.get_model("orders", "Category")
    Item = apps.get_model("orders", "Item")
    some_category = Category.objects.create(name="Category name")
    some_category.items.add(Item.objects.get(name="Item name").pk)
    # or for multiple items
    some_category.items.add(Item.objects.filter(...).values_list('pk', flat=True))

【讨论】:

  • 我实际上是在 1.8 上。我可以确认使用主键确实有效,但似乎不太理想。我宁愿依赖类型检查器提供的正确性。我已经删除了数据库并从 0001 重新执行了迁移,但情况仍然存在。
  • 您能检查一下id(Item)id(Category.items.rel.to) 是否确实不同?这可以解释这种行为。查看以前的迁移也可能有助于确定这是您的代码中的错误,还是 Django 中的错误。
  • 第一个给我一个 id,但第二个表达式触发 AttributeError: 'ReverseManyRelatedObjectsDescriptor' object has no attribute 'rel'
  • 哎呀-试试id(Category.items.field.related_model)
  • 是的,它们确实不同。我将使用相关的其他迁移来编辑我的原始问题。
猜你喜欢
  • 1970-01-01
  • 2021-12-20
  • 2018-10-21
  • 2015-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-09
  • 1970-01-01
相关资源
最近更新 更多