Python 在django中,当查询在原子上没有返回行时,如何向表中插入新行?

Python 在django中,当查询在原子上没有返回行时,如何向表中插入新行?,python,mysql,django,atomic,Python,Mysql,Django,Atomic,我正在写一个django应用程序。如果没有符合特定条件的行,我想在表中插入新行。例如: if not SomeModel.objects.filter(in_use=True).exist(): new_using = SomeModel(start_at=datetime.datetime.utcnow(), in_use=True) new_using.save() 我希望上面的代码是原子的,这样表中就不会有超过一行的in_use=True。我了解到django有一个原子(

我正在写一个django应用程序。如果没有符合特定条件的行,我想在表中插入新行。例如:

if not SomeModel.objects.filter(in_use=True).exist():
    new_using = SomeModel(start_at=datetime.datetime.utcnow(), in_use=True)
    new_using.save()
我希望上面的代码是原子的,这样表中就不会有超过一行的
in_use=True
。我了解到django有一个原子()上下文管理器。所以我正在考虑这样做:

with transaction.atomic():
   if not SomeModel.objects.filter(in_use=True).exist():
        new_using = SomeModel(start_at=datetime.datetime.utcnow(), in_use=True)
        new_using.save()
我对SQL不是很熟悉,所以我想知道上面的代码是否可以确保表中不超过一行同时具有
in_use=True
?如果没有,正确的方法是什么

谢谢。

transaction.atomic()确保您的代码块在数据库事务中运行;不幸的是,数据库事务通常不会保护您避免创建这样的两个冲突行。您的案例类似于臭名昭著的难插入问题。有关为什么这是一个棘手问题的更多信息,请参阅


实现这一点的方法将依赖于数据库,我对MySQL还不太熟悉,因此无法向您提供建议。一般的方法是获取表锁或使用可序列化的事务隔离级别,但您的数据库可能提供更好的解决方案。

您可以向数据库中的
SomeModel
表添加唯一约束。例如,在postgres中(如何在其他数据库中执行此操作):

然后对IntegrityError作出适当的反应:

try:
    # exist() query not needed
    new_using = SomeModel.objects.create(start_at=datetime.datetime.utcnow(),
                                         in_use=True)
except IntegrityError:
    # someone already using SomeModel data
    # try again or report to user
try:
    # exist() query not needed
    new_using = SomeModel.objects.create(start_at=datetime.datetime.utcnow(),
                                         in_use=True)
except IntegrityError:
    # someone already using SomeModel data
    # try again or report to user