django DoesNotExists 匹配查询不存在仅与 postgres 一起存在



我正在开发的assetsdjango 应用程序在 SQLite 上运行良好,但我面临着删除/更新大量记录的性能问题,所以我正在过渡到 PostgreSQL 数据库。

为此,我通过更新theapp/settings.py来配置PostgreSQL,从新的数据库开始并删除assets/migrations/目录。然后我正在运行:

./manage.py makemigrations assets
./manage.py migrate --run-syncdb
./manage.py createsuperuser

我有一个在注册post_create信号中调用的函数。它在创建Scan对象时运行扫描。在类assets.models.Scan中:

@classmethod
def post_create(cls, sender, instance, created, *args, **kwargs):
if not created:
return
from celery.result import AsyncResult
# get the domains for the project, from scan
print("debug: task = tasks.populate_endpoints.delay({})".format(instance.pk))
task = tasks.populate_endpoints.delay(instance.pk)

违规代码:

from celery import shared_task
....
import datetime
@shared_task
def populate_endpoints(scan_pk):
from .models import Scan, Project, 
from anotherapp.plugins.sensual import subdomains
scan = Scan.objects.get(pk=scan_pk) #<<<<<<<< django no like
new_entries_count = 0
project = Project.objects.get(id=scan.project.id)
....

由此产生的异常DoesNotExist引发:

debug: task = tasks.populate_endpoints.delay(2)
[2017-09-14 23:18:34,950: ERROR/ForkPoolWorker-8] Task assets.tasks.populate_endpoints[4555d329-2873-4184-be60-55e44c46a858] raised unexpected: DoesNotExist('Scan matching query does not exist.',)
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/celery/app/trace.py", line 374, in trace_task
R = retval = fun(*args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/celery/app/trace.py", line 629, in __protected_call__
return self.run(*args, **kwargs)
File "/usr/src/app/theapp/assets/tasks.py", line 12, in populate_endpoints
scan = Scan.objects.get(pk=scan_pk)

但是,通过./manage.py shell进行交互表示存在Scanpk == 2 的对象:

>>> from assets.models import Scan
>>> Scan.objects.all()
<QuerySet [<Scan: ACME Web Test Scan>]>
>>> s = Scan.objects.all().first()
>>> s.pk
2

我唯一的猜测是,在调用post_create函数时,尽管save()被调用,但 PostgreSQL 数据库中仍然不存在Scan对象。
SQLite 不会出现此问题。
另外,我还没有在stackoverflow上发现相关的相关问题,因为DoesNotExist异常看起来相当通用,并且是由许多事情引起的。 对此的任何想法将不胜感激。

这是由事务和隔离级别引起的众所周知的问题 - 有时在执行任务时事务尚未提交,如果您的隔离级别是 READ 提交,那么您确实无法从另一个进程读取此记录。Django 1.9引入了on_commit钩子作为解决方案。

注意:从技术上讲,这个问题是芹菜任务中缺少的 Django 相关对象的副本(竞争条件?),但接受的答案使用了django-transaction-hooks,此后它已被合并到 django 中。

相关内容

  • 没有找到相关文章

最新更新