Django:原子事务中的对象创建

Max*_*ore 6 django transactions atomic

我有一个简单的任务模型:

class Task(models.Model):

    name = models.CharField(max_length=255)
    order = models.IntegerField(db_index=True)
Run Code Online (Sandbox Code Playgroud)

还有一个简单的task_create视图:

def task_create(request):

    name = request.POST.get('name')
    order = request.POST.get('order')

    Task.objects.filter(order__gte=order).update(order=F('order') + 1)
    new_task = Task.objects.create(name=name, order=order)

    return HttpResponse(new_task.id)
Run Code Online (Sandbox Code Playgroud)

视图将新创建的现有任务转移+ 1,然后创建一个新任务.

并且有很多这种方法的用户,我想有一天会因为订购而出错,因为更新创建肯定应该一起执行.

所以,我只想保持谨慎,这足以避免任何数据损坏:

from django.db import transaction

def task_create(request):

    name = request.POST.get('name')
    order = request.POST.get('order')

    with transaction.atomic():
        Task.objects.select_for_update().filter(order__gte=order).update(order=F('order') + 1)
        new_task = Task.objects.create(name=name, order=order)

    return HttpResponse(new_task.id)
Run Code Online (Sandbox Code Playgroud)

1)可能select_for_updatefilter现有的任务创建行中应该做更多的事情Task.objects

2)return HttpResponse()位于何处?内部交易区块还是外部?

大thx

sol*_*oke 6

1)可能在任务创建行中应该做更多的事情,比如select_for_update在现有过滤之前Task.objects

不 - 你现在看起来很好,应该按照你想要的方式工作.

2)return HttpResponse()位于何处?内部交易区块还是外部?

是的,这很重要.无论事务是否成功,您都需要向客户端返回响应 - 因此它肯定需要在事务块之外.如果您在事务内部执行此操作,则如果事务失败,客户端将获得500 Server Error.

但是,如果事务失败,那么您将没有新的任务ID,并且无法在响应中返回该任务ID.因此,您可能需要根据事务是否成功返回不同的响应,例如:

from django.db import IntegrityError, transaction

try:
    with transaction.atomic():
        Task.objects.select_for_update().filter(order__gte=order).update(
                                                           order=F('order') + 1)
        new_task = Task.objects.create(name=name, order=order)
except IntegrityError:
    # Transaction failed - return a response notifying the client
    return HttpResponse('Failed to create task, please try again!')

# If it succeeded, then return a normal response
return HttpResponse(new_task.id)
Run Code Online (Sandbox Code Playgroud)