Django 测试套件在最新迁移中不存在的字段上抛出错误

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

以下简单测试,

from django.test import TestCase
    
    class TestSetup(TestCase):   
        def test_setUp(self):
            pdb.set_trace()
            # Code here deleted, it made no difference to the error.

抛出错误:

> Destroying old test database for alias 'default'... Traceback (most
> recent call last):   File
> "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/models/fields/__init__.py",
> line 1957, in get_prep_value
>     return float(value) ValueError: could not convert string to float: ''
> 
> The above exception was the direct cause of the following exception:
> 
> Traceback (most recent call last):   File "manage.py", line 22, in
> <module>
>     main()   File "manage.py", line 18, in main
>     execute_from_command_line(sys.argv)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/core/management/__init__.py",
> line 442, in execute_from_command_line
>     utility.execute()   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/core/management/__init__.py",
> line 436, in execute
>     self.fetch_command(subcommand).run_from_argv(self.argv)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/core/management/commands/test.py",
> line 24, in run_from_argv
>     super().run_from_argv(argv)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/core/management/base.py",
> line 412, in run_from_argv
>     self.execute(*args, **cmd_options)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/core/management/base.py",
> line 458, in execute
>     output = self.handle(*args, **options)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/core/management/commands/test.py",
> line 68, in handle
>     failures = test_runner.run_tests(test_labels)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/test/runner.py",
> line 1054, in run_tests
>     old_config = self.setup_databases(   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/test/runner.py",
> line 950, in setup_databases
>     return _setup_databases(   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/test/utils.py",
> line 221, in setup_databases
>     connection.creation.create_test_db(   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/backends/base/creation.py",
> line 78, in create_test_db
>     call_command(   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/core/management/__init__.py",
> line 194, in call_command
>     return command.execute(*args, **defaults)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/core/management/base.py",
> line 458, in execute
>     output = self.handle(*args, **options)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/core/management/base.py",
> line 106, in wrapper
>     res = handle_func(*args, **kwargs)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/core/management/commands/migrate.py",
> line 356, in handle
>     post_migrate_state = executor.migrate(   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/migrations/executor.py",
> line 135, in migrate
>     state = self._migrate_all_forwards(   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/migrations/executor.py",
> line 167, in _migrate_all_forwards
>     state = self.apply_migration(   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/migrations/executor.py",
> line 252, in apply_migration
>     state = migration.apply(state, schema_editor)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/migrations/migration.py",
> line 132, in apply
>     operation.database_forwards(   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/migrations/operations/fields.py",
> line 235, in database_forwards
>     schema_editor.alter_field(from_model, from_field, to_field)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/backends/base/schema.py",
> line 830, in alter_field
>     self._alter_field(   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/backends/postgresql/schema.py",
> line 287, in _alter_field
>     super()._alter_field(   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/backends/base/schema.py",
> line 1025, in _alter_field
>     new_default = self.effective_default(new_field)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/backends/base/schema.py",
> line 429, in effective_default
>     return field.get_db_prep_save(self._effective_default(field), self.connection)   File
> "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/models/fields/__init__.py",
> line 954, in get_db_prep_save
>     return self.get_db_prep_value(value, connection=connection, prepared=False)   File
> "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/models/fields/__init__.py",
> line 947, in get_db_prep_value
>     value = self.get_prep_value(value)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/models/fields/__init__.py",
> line 1959, in get_prep_value
>     raise e.__class__( ValueError: Field 'amount' expected a number but got ''.

“金额”字段确实存在,但在未加载任何测试的模型中:

models.py
    
class Appointment(models.Model):
    amount = models.FloatField(blank=True, default=0.0)

但为了防止在创建测试数据库的过程中实例化该模型,我将“default=0.0”迁移到“default='0.0'”(值周围的单引号)。同样的错误。

我还尝试使用 psql 手动删除 postgresql 测试数据库。

我正在开始测试

python manage.py test

还可以通过指定app_name:

python manage.py test giraffe

来自项目目录。

相关迁移,按顺序排列:

# Generated by Django 4.1.3 on 2023-01-10 22:58
from django.db import migrations, models   

class Migration(migrations.Migration):
    dependencies = [
        ('giraffe', '0014_appointment_notes'),
    ]
    operations = [
        migrations.AlterField(
            model_name='appointment',
            name='amount',
            field=models.FloatField(blank=True, default=''),
        ),
    ]

class Migration(migrations.Migration):
    dependencies = [
        ('giraffe', '0015_alter_appointment_amount'),
    ]
    operations = [
        migrations.AlterField(
            model_name='appointment',
            name='amount',
            field=models.FloatField(blank=True),
        ),
    ]

class Migration(migrations.Migration):
    dependencies = [
        ('giraffe', '0016_alter_appointment_amount'),
    ]
    operations = [
        migrations.AlterField(
            model_name='appointment',
            name='amount',
            field=models.FloatField(blank=True, default=0.0),
        ),
    ]

以及一些与具有“金额”字段的模型相关的早期迁移,但该模型已被删除,但仍显示在测试数据库中

...migrations.CreateModel(
            name='UnreimbursedMileage',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('mileage_rate_category', models.CharField(choices=[('FB22a', 'Federal Business Rate, Qtr. 1&2 2022'), ('FB22b', 'Federal Business Rate, Qtr. 3&4, 2022'), ('FB23', 'Federal Business Rate 2023')], default='FB22a', max_length=5)),
                ('num_miles', models.FloatField(blank=True, default=0)),
                ('amount', models.FloatField(blank=True, null=True)),
                ('for_appointment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, to='giraffe.appointment')),
            ],
            options={
                'verbose_name_plural': 'Unreimbursed Mileage',
            },
        ),

class Migration(migrations.Migration):
    dependencies = [
        ('giraffe', '0054_rename_to_do_next_time_todonexttime_and_more'),
    ]
    operations = [
        migrations.RemoveField(
            model_name='unreimbursedmileage',
            name='for_appointment',
        ),
        migrations.DeleteModel(
            name='Dummy',
        ),
        migrations.DeleteModel(
            name='UnreimbursedMileage',
        ),
    ]
django django-testing django-tests
1个回答
0
投票

回溯显示调用 alter_field 时会发生这种情况。

> line 235, in database_forwards
>     schema_editor.alter_field(from_model, from_field, to_field)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/backends/base/schema.py",
> line 830, in alter_field
>     self._alter_field(   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/backends/postgresql/schema.py",
> line 287, in _alter_field
>     super()._alter_field(   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/backends/base/schema.py",
> line 1025, in _alter_field
>     new_default = self.effective_default(new_field)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/backends/base/schema.py",
> line 429, in effective_default
>     return field.get_db_prep_save(self._effective_default(field), self.connection)   File
> "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/models/fields/__init__.py",
> line 954, in get_db_prep_save
>     return self.get_db_prep_value(value, connection=connection, prepared=False)   File
> "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/models/fields/__init__.py",
> line 947, in get_db_prep_value
>     value = self.get_prep_value(value)   File "/var/www/ptech/venv/lib/python3.8/site-packages/django/db/models/fields/__init__.py",
> line 1959, in get_prep_value
>     raise e.__class__( ValueError: Field 'amount' expected a number but got ''.

这是

migrations.AlterField
对象初始化的一部分。因此,当您创建
models.py
对象时,错误不在您的
models.FloatField
中。当您尝试创建
migrations.AlterField
对象时,就会发生这种情况。

查看最后一行,看看到底出了什么问题。

ValueError: Field 'amount' expected a number but got ''

因此,当您创建 SQL 数据库时,您需要让字段的类型与您尝试使用的数据类型相匹配。当您创建

AlterField
对象时,您在数据库中为字段“金额”指定了一个字符串默认值。但它是一个
FloatField
,所以我们需要一个浮动。

这是有问题的代码:

# Generated by Django 4.1.3 on 2023-01-10 22:58
from django.db import migrations, models   

class Migration(migrations.Migration):
    dependencies = [
        ('giraffe', '0014_appointment_notes'),
    ]
    operations = [
        migrations.AlterField(
            model_name='appointment',
            name='amount',
            field=models.FloatField(blank=True, default=''),
        ),
    ]

“金额”字段默认为空字符串“”,就像错误所示。我们需要一个漂浮物。

# Generated by Django 4.1.3 on 2023-01-10 22:58
from django.db import migrations, models   

class Migration(migrations.Migration):
    dependencies = [
        ('giraffe', '0014_appointment_notes'),
    ]
    operations = [
        migrations.AlterField(
            model_name='appointment',
            name='amount',
            field=models.FloatField(blank=True, default=0.0),
        ),
    ]

同样,所有

FloatField
对象在创建时都需要有一个默认的浮点值。
0014_appointment_notes
之后的下一次迁移,
0015_alter_appointment_amount
没有任何
FloatField
的默认值。将其更改为默认浮点值。

class Migration(migrations.Migration):
dependencies = [
    ('giraffe', '0015_alter_appointment_amount'),
]
operations = [
    migrations.AlterField(
        model_name='appointment',
        name='amount',
        field=models.FloatField(blank=True),
    ),
]

您可能尝试过改变这一点,但什么也没发生。

正如 Ron 在评论部分所说,解决方案是重置您的迁移。每个有 Django 应用程序的文件夹中都有一个隐藏文件夹,即每个文件夹都有自己的

models.py
。这是我们调用
makemigrations
之后创建的缓存文件,以加快
migrate
命令的速度,因为通常模型本身不会更改。添加新模型将更新此缓存,但更改模型则不会。确保使用 Unix 命令删除每个隐藏文件夹
.migrations
以及其中的所有文件和文件夹。

rm -r .migrations

运行

migrate
命令现在将自动运行命令
makemigrations
,因为
.migrations
文件夹不存在,现在必须创建才能迁移数据库。

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