If the `innocent_looking_function` would use transactions. And thus handles the `IntegrityError by` issuing a rollback, just like `get_or_create` does ( https://github.com/django/django/blob/1.6b4/django/db/models/query.py#L360-L390 ). Do you see the same behaviour in `my_func`?
-- Gert Mobile: +32 498725202 Twitter: @gvangool <http://twitter.com/gvangool> Web: http://gertvangool.be On Thu, Sep 19, 2013 at 2:38 PM, Richard Ward <[email protected]>wrote: > We're building a site that needs to use transactions, and have been doing > so against the 1.6 beta as 1.6 is nearly out and we thought it would be > easier to use the new transaction api, but we came across an unexpected > problem. > > Basically if you catch an IntegrityError and 'recover' from it, then your > transaction is still not committed. > > I'm posting this here rather than in django-users as its a feature in an > unreleased version and it seems like it a bug to me (apologies if it is the > wrong place). > > Take this code: > > def innocent_looking_function(): > "Makes sure that a MyModel with foo=1 exists" > try: > #imagine mymodel has a unique constraint on 'foo' > MyModel(foo=1).save() > except IntegrityError: > pass > > @transaction.atomic > def my_func(): > innocent_looking_function() > MyOtherModel(bar="hi").save() > > If you call 'my_func' when a MyModel with foo=1 exists, then the > transaction.atomic decorator will roll back the transaction, even though it > seems like everything is alright. 'my_func' doesn't know that > 'innocent_looking_func' may cause this behaviour, and as far as > 'innocent_looking_func' is concerned it has not done anything wrong - it > caught and ignored a harmless error. > > I had assumed that transaction.atomic would only roll back the transaction > if an exception was propagated through it (eg if innocent_looking_function > did not catch the error), that would seem like the natural way of doing > things. > > So what is the problem here? I assume it is one of: > > 1. 'innocent_looking_function' is badly written: it should not be > catching IntegrityErrors under any circumstances (though that seems like a > valid thing to do), it should instead use something like get_or_create. > 2. 'innocent_looking_function' should have 'with > transaction.atomic():' just inside the 'try' block, and presumably so > should every other bit of code where an IntegrityError is caught. But what > if 'innocent_looking_function' also gets used elsewhere that may not be > inside an atomic block? > 3. transaction.atomic is in some way buggy / oddly designed. > > IMO this behaviour makes code that looks valid (to me) not work in the > expected way. > > In case its relevant I'm using InnoDB tables on MySQL. > > So Is there a bug? Or am I using this incorrectly, or misunderstanding > something? > > Thanks, > > Richard > > -- > You received this message because you are subscribed to the Google Groups > "Django developers" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To post to this group, send email to [email protected]. > Visit this group at http://groups.google.com/group/django-developers. > For more options, visit https://groups.google.com/groups/opt_out. > -- You received this message because you are subscribed to the Google Groups "Django developers" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/django-developers. For more options, visit https://groups.google.com/groups/opt_out.
