数据迁移在导入时触发查询
data migration is triggering a query at import time
我的最后一次迁移是触发个人资料应用缩略图更新的数据迁移
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
我认为这是因为我的数据迁移在导入时触发了查询,所以它比迁移本身早 运行s。
评论触发代码暂时解决问题,我需要一个真正的解决方案,拜托
更新 这里是完整的回溯:
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...
迁移代码 运行ning 使用 Hostorical model,这就是为什么您不能直接导入模型,而是需要通过 apps.get_model(...)
获取它们的原因。执行迁移文件时,它 运行s 带有迁移时您 User
模型的版本,没有 is_daleted
字段。
但是,您从迁移中调用的 celery 任务 make_image_thumbnail
并未使用此托管模型。据任务所知,User
模型有一个 is_deleted
字段,它根据您的 models.py
使用最新版本的模型。
当您从第一次迁移调用任务时,数据库中尚不存在该列。
为什么在测试中出现问题,而在您 运行 手动迁移时却没有?通常,我 运行 我的测试 CELERY_TASK_ALWAYS_EAGER = True
,你可能也是这样做的。 运行ning 测试时,您的任务在第一次迁移中同步执行。当您手动执行迁移时,它被禁用,并且您的任务实际上是在第二次迁移后 运行。
我在这里也同意@dirkgroten:我建议在迁移中复制您的任务代码。如果因为它使用自定义方法或属性而太复杂,我建议不要在数据迁移中这样做。您有几个选择:
- 运行手动任务
- 您可以使用 custom admin command
- 暂时介绍一个
post_migrate
signal handler
更一般地说,运行从迁移中获取 celery 任务在 IMO 中是个坏主意,我建议不要这样做。
我的最后一次迁移是触发个人资料应用缩略图更新的数据迁移
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
我认为这是因为我的数据迁移在导入时触发了查询,所以它比迁移本身早 运行s。
评论触发代码暂时解决问题,我需要一个真正的解决方案,拜托
更新 这里是完整的回溯:
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...
迁移代码 运行ning 使用 Hostorical model,这就是为什么您不能直接导入模型,而是需要通过 apps.get_model(...)
获取它们的原因。执行迁移文件时,它 运行s 带有迁移时您 User
模型的版本,没有 is_daleted
字段。
但是,您从迁移中调用的 celery 任务 make_image_thumbnail
并未使用此托管模型。据任务所知,User
模型有一个 is_deleted
字段,它根据您的 models.py
使用最新版本的模型。
当您从第一次迁移调用任务时,数据库中尚不存在该列。
为什么在测试中出现问题,而在您 运行 手动迁移时却没有?通常,我 运行 我的测试 CELERY_TASK_ALWAYS_EAGER = True
,你可能也是这样做的。 运行ning 测试时,您的任务在第一次迁移中同步执行。当您手动执行迁移时,它被禁用,并且您的任务实际上是在第二次迁移后 运行。
我在这里也同意@dirkgroten:我建议在迁移中复制您的任务代码。如果因为它使用自定义方法或属性而太复杂,我建议不要在数据迁移中这样做。您有几个选择:
- 运行手动任务
- 您可以使用 custom admin command
- 暂时介绍一个
post_migrate
signal handler
更一般地说,运行从迁移中获取 celery 任务在 IMO 中是个坏主意,我建议不要这样做。