简体   繁体   English

如果在Django中删除了对象或保释,如何更新它

[英]How to update an object or bail if it has been deleted in Django

I have a Django app saving objects to the database and a celery task that periodically does some processing on some of those objects. 我有一个Django应用程序将对象保存到数据库和一个芹菜任务,定期对其中一些对象进行一些处理。 The problem is that the user can delete an object after it has been selected by the celery task for processing, but before the celery task has actually finished processing and saving it. 问题是用户可以在芹菜任务选择对象之后删除对象,但是芹菜任务实际完成处理并保存之前。 So when the celery task does call .save() , the object re-appears in the database even though the user deleted it. 因此,当celery任务调用.save() ,即使用户删除了对象,该对象也会重新出现在数据库中。 Which is really spooky for users, of course. 当然,这对用户来说真的很怪异。

So here's some code showing the problem: 所以这里有一些显示问题的代码:

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()

I thought about trying to fix it by adding an atomic block and a transaction to test if the object actually exists before saving it: 我想通过添加原子块和事务来尝试修复它,以在保存之前测试对象是否实际存在:

@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")

Is this the correct pattern to do this sort of thing? 这是做这种事情的正确模式吗? I mean, I'll find out if it works within a few days of running it in production, but it would be nice to know if there are any other well-accepted patterns for accomplishing this sort of thing. 我的意思是,我会发现它是否能在生产中运行它的几天内发挥作用,但是知道是否有任何其他广为接受的模式来完成这类事情会很好。

What I really want is to be able to update an object if it still exists in the database . 我真正想要的是能够更新对象, 如果它仍然存在于数据库中 I'm ok with the race between user edits and edits from the process_thing , and I can always throw in a refresh_from_db just before the process_thing to minimize the time during which user edits would be lost. 我很喜欢用户编辑和process_thing编辑之间的竞争,我总是可以在process_thing之前输入refresh_from_db ,以最大限度地减少用户编辑丢失的时间。 But I definitely can't have objects re-appearing after the user has deleted them. 但是在用户删除对象后,我肯定无法重新显示对象。

if you open a transaction for the time of processing of celery task, you should avoid such a problems: 如果你在处理芹菜任务时打开一个事务,你应该避免这样的问题:

@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()

sometimes, you would like to report to the frontend, that you are working on the data, so you can add select_for_update() to your queryset (most probably in get_things_for_processing), then in the code responsible for deletion you need to handle errors when db will report that specific record is locked. 有时,您想向前端报告您正在处理数据,因此您可以将select_for_update()添加到您的查询集(最有可能是在get_things_for_processing中),然后在负责删除的代码中,您需要在db时处理错误将报告特定记录已被锁定。

For now, it seems like the pattern of "select again atomically, then save" is sufficient: 就目前而言,似乎“以原子方式再次选择,然后保存”的模式就足够了:

@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")

(this is the same code as in my original question). (这与我原来的问题中的代码相同)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM