#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.