如果对象或保释已在 Django 中删除,如何更新它
How to update an object or bail if it has been deleted in Django
我有一个 Django 应用程序将对象保存到数据库,还有一个 celery 任务定期对其中一些对象进行一些处理。问题是用户可以删除一个对象 after 它已被 celery 任务选择进行处理,但 before celery 任务实际上已经完成处理并保存。因此,当 celery 任务确实调用 .save()
时,即使用户删除了该对象,该对象也会重新出现在数据库中。当然,这对用户来说真的很恐怖。
下面是一些显示问题的代码:
def my_delete_view(request, pk):
thing = Thing.objects.get(pk=pk)
thing.delete()
return HttpResponseRedirect('yay')
@app.task
def my_periodic_task():
things = get_things_for_processing()
# if the delete happens anywhere between here and the .save(), we're hosed
for thing in things:
process_thing(thing) # could take a LONG time
thing.save()
我想尝试通过添加一个原子块和一个事务来修复它,以在保存之前测试该对象是否确实存在:
@app.task
def my_periodic_task():
things = Thing.objects.filter(...some criteria...)
for thing in things:
process_thing(thing) # could take a LONG time
try:
with transaction.atomic():
# just see if it still exists:
unused = Thing.objects.select_for_update().get(pk=thing.pk)
# no exception means it exists. go ahead and save the
# processed version that has all of our updates.
thing.save()
except Thing.DoesNotExist:
logger.warning("Processed thing vanished")
这是做这类事情的正确模式吗?我的意思是,我会在 运行 投入生产后的几天内确定它是否有效,但很高兴知道是否有任何其他广为接受的模式来完成此类事情。
我真正想要的是能够更新一个对象如果它仍然存在于数据库中。我可以接受用户编辑和来自 process_thing
的编辑之间的竞争,而且我总是可以在 process_thing
之前添加一个 refresh_from_db
以最大限度地减少用户编辑的时间丢失。但是我绝对不能让对象在用户删除后重新出现。
如果在处理celery任务的时候开启事务,应该避免这样的问题:
@app.task
@transaction.atomic
def my_periodic_task():
things = get_things_for_processing()
# if the delete happens anywhere between here and the .save(), we're hosed
for thing in things:
process_thing(thing) # could take a LONG time
thing.save()
有时,您想向前端报告您正在处理数据,因此您可以将 select_for_update()
添加到您的查询集中(很可能在 get_things_for_processing 中),然后在负责删除的代码当数据库报告特定记录已锁定时,您需要处理错误。
目前看来,"select again atomically, then save" 的模式就足够了:
@app.task
def my_periodic_task():
things = Thing.objects.filter(...some criteria...)
for thing in things:
process_thing(thing) # could take a LONG time
try:
with transaction.atomic():
# just see if it still exists:
unused = Thing.objects.select_for_update().get(pk=thing.pk)
# no exception means it exists. go ahead and save the
# processed version that has all of our updates.
thing.save()
except Thing.DoesNotExist:
logger.warning("Processed thing vanished")
(这与我原来问题中的代码相同)。
我有一个 Django 应用程序将对象保存到数据库,还有一个 celery 任务定期对其中一些对象进行一些处理。问题是用户可以删除一个对象 after 它已被 celery 任务选择进行处理,但 before celery 任务实际上已经完成处理并保存。因此,当 celery 任务确实调用 .save()
时,即使用户删除了该对象,该对象也会重新出现在数据库中。当然,这对用户来说真的很恐怖。
下面是一些显示问题的代码:
def my_delete_view(request, pk):
thing = Thing.objects.get(pk=pk)
thing.delete()
return HttpResponseRedirect('yay')
@app.task
def my_periodic_task():
things = get_things_for_processing()
# if the delete happens anywhere between here and the .save(), we're hosed
for thing in things:
process_thing(thing) # could take a LONG time
thing.save()
我想尝试通过添加一个原子块和一个事务来修复它,以在保存之前测试该对象是否确实存在:
@app.task
def my_periodic_task():
things = Thing.objects.filter(...some criteria...)
for thing in things:
process_thing(thing) # could take a LONG time
try:
with transaction.atomic():
# just see if it still exists:
unused = Thing.objects.select_for_update().get(pk=thing.pk)
# no exception means it exists. go ahead and save the
# processed version that has all of our updates.
thing.save()
except Thing.DoesNotExist:
logger.warning("Processed thing vanished")
这是做这类事情的正确模式吗?我的意思是,我会在 运行 投入生产后的几天内确定它是否有效,但很高兴知道是否有任何其他广为接受的模式来完成此类事情。
我真正想要的是能够更新一个对象如果它仍然存在于数据库中。我可以接受用户编辑和来自 process_thing
的编辑之间的竞争,而且我总是可以在 process_thing
之前添加一个 refresh_from_db
以最大限度地减少用户编辑的时间丢失。但是我绝对不能让对象在用户删除后重新出现。
如果在处理celery任务的时候开启事务,应该避免这样的问题:
@app.task
@transaction.atomic
def my_periodic_task():
things = get_things_for_processing()
# if the delete happens anywhere between here and the .save(), we're hosed
for thing in things:
process_thing(thing) # could take a LONG time
thing.save()
有时,您想向前端报告您正在处理数据,因此您可以将 select_for_update()
添加到您的查询集中(很可能在 get_things_for_processing 中),然后在负责删除的代码当数据库报告特定记录已锁定时,您需要处理错误。
目前看来,"select again atomically, then save" 的模式就足够了:
@app.task
def my_periodic_task():
things = Thing.objects.filter(...some criteria...)
for thing in things:
process_thing(thing) # could take a LONG time
try:
with transaction.atomic():
# just see if it still exists:
unused = Thing.objects.select_for_update().get(pk=thing.pk)
# no exception means it exists. go ahead and save the
# processed version that has all of our updates.
thing.save()
except Thing.DoesNotExist:
logger.warning("Processed thing vanished")
(这与我原来问题中的代码相同)。