summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2013-07-03 07:59:35 -0400
committerTim Graham <timograham@gmail.com>2013-07-04 08:34:00 -0400
commitfa37f45c32c8fa7c6909b72e94b9d90e6efe7ed9 (patch)
tree32625250e5d9a7a27ab16c093b95dc616a078aa5
parent9c501e6638dce82b579fc769c52664246a336371 (diff)
[1.5.x] Fixed #12579 -- Noted QuerySet.get_or_create() depends on database unique constraints.
Thanks timmolendijk, jdunck, vijay_shanker, and loic84. Backport of 428de2e339 from master.
-rw-r--r--docs/ref/models/querysets.txt33
1 files changed, 22 insertions, 11 deletions
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
index 7ef6a4feee..1b008e42b9 100644
--- a/docs/ref/models/querysets.txt
+++ b/docs/ref/models/querysets.txt
@@ -1297,15 +1297,14 @@ get_or_create
.. method:: get_or_create(**kwargs)
-A convenience method for looking up an object with the given kwargs, creating
-one if necessary.
+A convenience method for looking up an object with the given ``kwargs``,
+creating one if necessary.
Returns a tuple of ``(object, created)``, where ``object`` is the retrieved or
created object and ``created`` is a boolean specifying whether a new object was
created.
-This is meant as a shortcut to boilerplatish code and is mostly useful for
-data-import scripts. For example::
+This is meant as a shortcut to boilerplatish code. For example::
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
@@ -1353,13 +1352,25 @@ when you're using manually specified primary keys. If an object needs to be
created and the key already exists in the database, an
:exc:`~django.db.IntegrityError` will be raised.
-Finally, a word on using ``get_or_create()`` in Django views. As mentioned
-earlier, ``get_or_create()`` is mostly useful in scripts that need to parse
-data and create new records if existing ones aren't available. But if you need
-to use ``get_or_create()`` in a view, please make sure to use it only in
-``POST`` requests unless you have a good reason not to. ``GET`` requests
-shouldn't have any effect on data; use ``POST`` whenever a request to a page
-has a side effect on your data. For more, see `Safe methods`_ in the HTTP spec.
+This method is atomic assuming correct usage, correct database configuration,
+and correct behavior of the underlying database. However, if uniqueness is not
+enforced at the database level for the ``kwargs`` used in a ``get_or_create``
+call (see :attr:`~django.db.models.Field.unique` or
+:attr:`~django.db.models.Options.unique_together`), this method is prone to a
+race-condition which can result in multiple rows with the same parameters being
+inserted simultaneously.
+
+If you are using MySQL, be sure to use the ``READ COMMITTED`` isolation level
+rather than ``REPEATABLE READ`` (the default), otherwise you may see cases
+where ``get_or_create`` will raise an :exc:`~django.db.IntegrityError` but the
+object won't appear in a subsequent :meth:`~django.db.models.query.QuerySet.get`
+call.
+
+Finally, a word on using ``get_or_create()`` in Django views: please make sure
+to use it only in ``POST`` requests unless you have a good reason not to
+``GET`` requests shouldn't have any effect on data; use ``POST`` whenever a
+request to a page as a side effect on your data. For more, see `Safe methods`_
+in the HTTP spec.
.. _Safe methods: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1