As a followup to the suggestion of MyModel.objects.filter(money__gte = value, pk = self.pk).update(F...)
Here's an example: We have testapp/models.py: from django.db import models class TestModel(models.Model): balance = models.IntegerField() >>> from django.db.models import F >>> TestModel.objects.create(balance = 5) #Pk will be 1 I just create one. >>> import logging >>> l = logging.getLogger('django.db.backends') >>> l.setLevel(logging.DEBUG) >>> l.addHandler(logging.StreamHandler()) >>> TestModel.objects.filter(balance__gte = 4, pk = 1).update(balance = F('balance') - 4) (0.001) UPDATE "testapp_testmodel" SET "balance" = "testapp_testmodel"."balance" - 4 WHERE ("testapp_testmodel"."balance" >= 4 AND "testapp_testmodel"."id" = 1 ); args=(4, 4, 1) 1 >>> TestModel.objects.filter(balance__gte = 4, pk = 1).update(balance = F('balance') - 4) (0.000) UPDATE "testapp_testmodel" SET "balance" = "testapp_testmodel"."balance" - 4 WHERE ("testapp_testmodel"."balance" >= 4 AND "testapp_testmodel"."id" = 1 ); args=(4, 4, 1) 0 *So this seems to generate a single SQL statement.* * * *I'm not totally familiar with database administration though, so as** Melvyn rightly pointed out, it's always better if you can get the extra security of having an SQL constraint into your dabatase and wrap your queries in a transaction (as you'll probably be adding a line to the statement if the withdrawal succeeds).* * * 2012/8/20 Thomas Orozco <g.orozco.tho...@gmail.com> > A few suggestions : > > Circumvent the problem with smarter design: don't store the money on the > object, make the user's money the sum of all their transactions (credit - > debit). > You get lesser performance, but you also get history! > > Maybe you could try (not sure about that): > > MyModel.objects.filter(money__gte = value, pk = self.pk).update(F...) > > and inspect the return value (number of updated rows!). > Now, you'd need to make sure django does that in a single statement. > > If that doesn't work, I think update is the way to go anyway, but it might > get a bit messy. > > F... is an F object whose syntax I don't have off the top of my head. > Le 20 août 2012 18:54, "Sebastien Flory" <sfl...@gmail.com> a écrit : > > Hi everyone, >> >> I'm looking for the proper django way to do an update of an attribute on >> my model instance, but only if the attribute current value is checked >> agains't a condition, in an atomic way, something like this: >> >> def use_money(self, value): >> begin_transaction() >> real_money = F('money') >> if real_money >= value: >> self.money = F('money') - value >> self.save() >> end_transaction() >> >> I want to make sure that I avoid race condition so money never goes below >> 0. >> >> Can you help me out? >> >> Thanks, >> >> Sebastien >> >> -- >> You received this message because you are subscribed to the Google Groups >> "Django users" group. >> To view this discussion on the web visit >> https://groups.google.com/d/msg/django-users/-/hr1fBuAcX3kJ. >> To post to this group, send email to django-users@googlegroups.com. >> To unsubscribe from this group, send email to >> django-users+unsubscr...@googlegroups.com. >> For more options, visit this group at >> http://groups.google.com/group/django-users?hl=en. >> > -- You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com. To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-users?hl=en.