仅在运行测试时,我才收到“无此类列”错误

问题描述 投票:0回答:1

编辑: 我通过数据库删除了,从头开始迁移时会发生这种情况,所以我的基本迁移顺序似乎有问题。

基本上我已经(步骤 1 实际上是步骤 14,但是有)

  1. 创建模型

  2. 用夹具填充模型

  3. 向模型添加新列

当执行到第 2 步时,它会因“列不存在”错误而终止。

此时数据库没有该列,它所应用的夹具也没有对其进行任何引用。


也许这遗漏了一些关键细节并暴露了我对 django 的相对陌生,但我试图将我的问题隔离到最少的步骤来重现问题。

启动状态:应用程序运行良好,测试全部通过。

  1. 向现有模型添加一个可为空的列。
  2. 进行迁移
  3. 迁移

新状态:应用程序运行良好,运行测试会产生错误。

Creating test database for alias 'default'...
Found 23 test(s).
Installed 5 object(s) from 1 fixture(s)
Traceback (most recent call last):
  File "/home/f/.virtualenvs/mgmt/lib/python3.10/site-packages/django/db/backends/utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "/home/f/.virtualenvs/mgmt/lib/python3.10/site-packages/django/db/backends/sqlite3/base.py", line 357, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: no such column: recommended_for_text

recommend_for_text 是新列的名称。

recommended_for_text = models.CharField(null=True, blank=True, max_length=256)

它按预期显示在应用程序的我的视图中,只是运行测试就给我带来了问题。

更新: 更改之前运行测试输出:

Found 23 test(s).
Creating test database for alias 'default'...
Installed 5 object(s) from 1 fixture(s)
Installed 9 object(s) from 1 fixture(s)
System check identified no issues (0 silenced).
.......................
----------------------------------------------------------------------
Ran 23 tests in 2.286s

OK
Destroying test database for alias 'default'...

及之后:

Found 23 test(s).
Creating test database for alias 'default'...
Installed 5 object(s) from 1 fixture(s)
Traceback (most recent call last):
  File "/home/f/.local/lib/python3.10/site-packages/django/db/backends/utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "/home/f/.local/lib/python3.10/site-packages/django/db/backends/sqlite3/base.py", line 357, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: no such column: recommended_for_text

0016_migration.py:

# Generated by Django 4.1.13 on 2024-04-25 17:34

from django.db import migrations, models


    class Migration(migrations.Migration):
    
        dependencies = [
            ("sites", "0015_populate_plans"),
        ]
    
        operations = [
            migrations.AddField(
                model_name="plan",
                name="recommended_for_text",
                field=models.CharField(blank=True, max_length=256, null=True),
            ),
        ]

0015_migration.py:(我认为这一定是失败的原因,但在添加新列和0016之前它可以工作)

# Generated by Django 4.1.10 on 2024-04-03 14:02
from django.core.management import call_command
from django.db import migrations


def load_plans(apps, schema_editor):
    call_command('loaddata', 'plans.json', app_label='sites')


class Migration(migrations.Migration):

    dependencies = [
        ("sites", "0014_sitecommandlog_note"),
    ]

    operations = [
        migrations.RunPython(load_plans),
    ]

plans.json 有一堆这样的记录(特别是没有Recommended_for_text 字段,因为它还不存在)

{
  "model": "sites.plan",
  "pk": 2,
  "fields": {
    "portal_plan_name": "Basic",
    "plan_sku": "plan-basic_small-contract-annual-1",
    "traffic_limits": "35000",
    "annual_plan_charge": "224.00",
    "is_active": true
  }
}

更奇怪的是我尝试从tests.py中消除实际测试 这运行得很好

from unittest import main
from django.test import TestCase


if __name__ == '__main__':
    main()

但这会引发 no such columns 异常

from unittest import main
from django.test import TestCase

class SleepTest(TestCase):
    def test_sleep(self):
        from time import sleep
        sleep(10)

if __name__ == '__main__':
    main()
django django-models
1个回答
0
投票

你的

0015_migration
很有问题。根据经验,您不应在迁移中调用
loaddata
命令,因为它将使用当前模型而不是 历史模型,这意味着当您仅添加迁移时,迁移可能会起作用,但可能会失败未来当模型发生更多变化时。

现在您可以执行以下操作:

0015_migration
中将
load_plans
的参数中的
RunPython
替换为
RunPython.noop

from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("sites", "0014_sitecommandlog_note"),
    ]

    operations = [
        migrations.RunPython(migrations.RunPython.noop),
    ]

接下来,如果您真的想使用

loaddata
命令,请从迁移系统外部进行操作。如果您确实想通过迁移加载数据,请考虑进行不依赖于 loaddata 命令的
数据迁移
。如果您想通过数据迁移加载固定装置,您可以按照此问题中的指导来模拟
loaddata
的作用:使用 Django 1.7+ 和数据迁移加载初始数据

© www.soinside.com 2019 - 2024. All rights reserved.