【问题标题】:How to update an object or bail if it has been deleted in Django如果已在 Django 中删除,如何更新对象或保释
【发布时间】:2016-05-15 05:44:14
【问题描述】:

我有一个 Django 应用程序将对象保存到数据库和一个 celery 任务,它定期对其中一些对象进行一些处理。问题是用户可以删除一个对象它已被 celery 任务选择进行处理,但 之前 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,以最大限度地减少用户编辑丢失的时间。但我绝对不能让对象在用户删除它们后重新出现。

【问题讨论】:

    标签: python django locking celery database-locking


    【解决方案1】:

    如果你在处理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 中),然后在您需要处理的负责删除的代码中db 将报告特定记录已锁定时的错误。

    【讨论】:

    • 嗯,我宁愿将其锁定尽可能短的时间(如我的问题所示)。与我提出的方法相比,一直锁定它有什么好处吗?
    • 是 - 如果您正在使用存储在此记录中的数据,并且您必须确保从您开始处理到结束 - 没有任何人会更改此记录
    • 但这不是我需要的:)。如问题所述,我可以接受用户编辑和process_thing 的编辑之间的竞争。我只是不希望删除的对象重新出现。这是我唯一要防止的事情。
    【解决方案2】:

    目前看来,“再次原子选择,然后保存”的模式就足够了:

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

    (这与我原来的问题中的代码相同)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-11
      • 1970-01-01
      • 2019-10-29
      • 2013-10-03
      • 2011-01-12
      • 1970-01-01
      • 2012-07-23
      相关资源
      最近更新 更多