How to update an object or instruct if it was deleted in Django

I have a Django application for storing objects in a database and a celery task that periodically do some processing on some of these objects. The problem is that the user can delete the object after it has been selected by the celery task for processing, but before the celery task actually completed processing and saving. Therefore, when the celery task invokes .save(), the object reappears in the database, even if the user deleted it. Of course, this is really creepy for users.

So, here is the code that shows 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 was thinking of trying to fix this by adding an atomic block and a transaction to check if the object really 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")

? , , , , - .

, , . process_thing, refresh_from_db process_thing, , . , .

+4
2

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

( , ).

-1

, :

@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), , , , db , .

0

All Articles