How can I atomically compare-exchange-save a value of Django
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
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
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.
# License code already redeemed, don't deposit another license.
# Handle exception
What you are looking for is the
update function on a QuerySet object.
Depending on the value, you can do a comparison with Case, When objects - check out the docs on conditional updates NOTE that link is for 1.10 - Case/When came in in 1.8.
You might also find utility in using
F which is used to reference a value in a field.
I need to update a value in my model Model:
(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())))
If you need to use an
F object, just reference it on the right hand side of the equals in the update expression.
The update doesn't necessitate the use of
transaction.atomic() context manager but if you need to do any other database operations you should continue to wrap that code with
You may also like to use the queryset
select_for_update method that implements row locks when the queryset is executed docs.