我如何以原子方式比较 - 交换 - 保存Django Model
实例Field
的值? (使用PostgreSQL作为数据库后端)。
一个示例用例是确保具有相似内容的多个帖子(例如,相同表单的提交)仅生效一次,而不依赖于不安全且仅有时工作的客户端javascript或服务器端跟踪形式UUID,这对于恶意的多个帖子是不安全的。
例如:
def compare_exchange_save(model_object, field_name, comp, exch):
# How to implement?
....
from django.views.generic.edit import FormView
from django.db import transaction
from my_app.models import LicenseCode
class LicenseCodeFormView(FormView):
def post(self, request, ...):
# Get object matching code entered in form
license_code = LicenseCode.objects.get(...)
# Safely redeem the code exactly once
# No change is made in case of error
try:
with transaction.atomic()
if compare_exchange_save(license_code, 'was_redeemed', False, True):
# Deposit a license for the user with a 3rd party service. Raises an exception if it fails.
...
else:
# License code already redeemed, don't deposit another license.
pass
except:
# Handle exception
...
答案 0 :(得分:1)
您正在寻找的是QuerySet对象上的update
函数。
根据值,您可以与案例进行比较,当对象时 - 查看conditional updates上的文档注意该链接是针对1.10 - 案例/何时进入1.8
您可能还会在使用F
时找到实用程序,该(Model.objects
.filter(id=my_id)
.update(field_to_be_updated=Case(
When(my_field=True, then=Value(get_new_license_string()),
default=Value(''),
output_field=models.CharField())))
用于引用字段中的值。
例如:
我需要更新模型中的值:
F
如果您需要使用transaction.atomic()
对象,只需在更新表达式中等号的右侧引用它。
更新不需要使用transaction.atomic()
上下文管理器,但如果您需要执行任何其他数据库操作,则应继续使用select_for_update
编辑:
您可能还想使用在执行查询集时实现行锁的queryset %s/\(\d\+\)/"\1"
方法{。{3}}。