0

我的最后一次迁移是触发配置文件应用程序缩略图更新的数据迁移

def trigger_thumbnails_update(apps, schema_editor):
    """
    Trigger thumbnails update for profile app
    """
    User = apps.get_model('profile', 'User')
    for user in User.objects.all():
        if user.photo:
            make_image_thumbnail.delay()


class Migration(migrations.Migration):

    dependencies = [
        ('profile', '0008_auto_20190611_2120'),
    ]

    operations = [
        migrations.RunPython(trigger_thumbnails_update),
    ]

之后,我添加了一个名为is_daleted, 并运行的字段makemigrations

class Migration(migrations.Migration):

    dependencies = [
        ('profile', '0009_trigger_thumbnails_update'),
    ]

    operations = [
        migrations.AddField(
            model_name='user',
            name='is_deleted',
            field=models.BooleanField(default=False),
        ),
    ]

这很好,但是当我运行测试(pytest)时,我得到了那个错误:django.db.utils.ProgrammingError: column profile_user.is_deleted does not exist

我认为这是由于我的数据迁移在导入时触发了查询,因此它在迁移本身之前运行。

评论触发代码暂时解决问题,我需要一个真正的解决方案,请

这里的更新是完整的回溯:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: column profile_user.is_deleted does not exist
LINE 1: ...r"."is_onboarded", "profile_user"."last_request", "profile_u...
                                                             ^


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/celery/app/trace.py", line 385, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/celery/app/trace.py", line 648, in __protected_call__
    return self.run(*args, **kwargs)
  File "/opt/app/apps/utils/tasks.py", line 18, in make_image_thumbnail
    obj = Model.objects.get(pk=pk)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 393, in get
    num = len(clone)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 250, in __len__
    self._fetch_all()
  File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 1183, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 54, in __iter__
    results = comp...
4

1 回答 1

0

迁移代码使用Hostorical 模型运行,这就是为什么您不能直接导入模型,而需要通过apps.get_model(...). 执行迁移文件时,它将使用User迁移时的模型版本运行,不带该is_daleted字段。

但是,make_image_thumbnail您从迁移中调用的 celery 任务并未使用此主机模型。据任务所知,User模型有一个is_deleted字段,它使用模型的最新版本,根据您的models.py.

当您从第一次迁移中调用任务时,数据库中尚不存在该列。

为什么在测试中会出现问题,而不是在手动运行迁移时出现问题?通常,我使用 运行我的测试CELERY_TASK_ALWAYS_EAGER = True,这可能也是你所做的。运行测试时,您的任务会在第一次迁移中同步执行。当您手动执行迁移时,此功能被禁用,您的任务实际上是在第二次迁移之后运行的。

我在这里也同意@dirkgroten:我建议在迁移中复制您的任务代码。如果这太复杂了,因为它使用自定义方法或属性,我建议不要在数据迁移中这样做。你有几个选择:

更一般地说,从迁移中运行 celery 任务是 IMO 的一个坏主意,我建议不要这样做。

于 2019-08-23T10:08:37.870 回答