#12579: QuerySet.get_or_create()'s behavior depends on database's uniqueness
restrictions
-----------------------------------------------------------------+----------
 Reporter:  timmolendijk                                         |       Owner: 
 nobody    
   Status:  new                                                  |   Milestone: 
           
Component:  Database layer (models, ORM)                         |     Version: 
 1.0       
 Keywords:  get_or_create concurrency race unique documentation  |       Stage: 
 Unreviewed
Has_patch:  0                                                    |  
-----------------------------------------------------------------+----------
 {{{QuerySet.get_or_create()}}} works as expected, IFF the kwargs that are
 provided correspond to database columns with appropriate uniqueness
 restrictions. In other words: {{{get_or_create()}}} depends on an
 IntegrityError being raised under certain circumstances. If you have a
 database that does not do this, f.e. because a table's uniqueness logic
 cannot be expressed with the database's {{{UNIQUE}}} construct.

 For instance:

 Given the following table: {{{CREATE TABLE t1 (i INT, flag TINYINT,
 parent_id INT, PRIMARY KEY (i)) ENGINE = InnoDB;}}}
 An additional restriction, one which cannot be expressed in the table
 definition, is that only one record can exist with {{{flag=1}}} for every
 given {{{parent_id}}}.
 The following code gives the impression that we enforce said restriction:
 {{{T1.objects.get_or_create(parent_id=3, flag=1)}}}.
 But this is a false impression, as two concurrent transactions executing
 this same code can (and will on a regular basis) result in two records
 with {{{parent_id=3}}} and {{{flag=1}}}. This is the result of both
 transactions trying to {{{get()}}} a record with {{{parent_id=3}}} and
 {{{flag=1}}} before any of them has inserted this record. So both
 transactions will conclude they need to {{{create{}}}} the record, which
 will be allowed by the database and thus an inconsistency will enter the
 database.

 Now the ideal scenario would be that race conditions are prevented
 regardless of how the underlying database table is defined. But I am not
 sure if this is a feasible approach. At the very least I think people who
 use {{{get_or_create()}}} need to be aware that it can give rise to
 concurrency issues, unless they follow some basic guidelines... something
 like that.

-- 
Ticket URL: <http://code.djangoproject.com/ticket/12579>
Django <http://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.


Reply via email to