Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #12579 -- Noted QuerySet.get_or_create() depends on database un…

…ique constraints.

Thanks timmolendijk, jdunck, vijay_shanker, and loic84.
  • Loading branch information...
commit 428de2e3394873810645010020d65841ab72bb14 1 parent 231e31c
Tim Graham authored July 03, 2013

Showing 1 changed file with 21 additions and 10 deletions. Show diff stats Hide diff stats

  1. 31  docs/ref/models/querysets.txt
31  docs/ref/models/querysets.txt
@@ -1334,7 +1334,7 @@ get_or_create
1334 1334
 
1335 1335
 .. method:: get_or_create(**kwargs)
1336 1336
 
1337  
-A convenience method for looking up an object with the given kwargs (may be
  1337
+A convenience method for looking up an object with the given ``kwargs`` (may be
1338 1338
 empty if your model has defaults for all fields), creating one if necessary.
1339 1339
 
1340 1340
 .. versionchanged:: 1.6
@@ -1345,8 +1345,7 @@ Returns a tuple of ``(object, created)``, where ``object`` is the retrieved or
1345 1345
 created object and ``created`` is a boolean specifying whether a new object was
1346 1346
 created.
1347 1347
 
1348  
-This is meant as a shortcut to boilerplatish code and is mostly useful for
1349  
-data-import scripts. For example::
  1348
+This is meant as a shortcut to boilerplatish code. For example::
1350 1349
 
1351 1350
     try:
1352 1351
         obj = Person.objects.get(first_name='John', last_name='Lennon')
@@ -1394,13 +1393,25 @@ when you're using manually specified primary keys. If an object needs to be
1394 1393
 created and the key already exists in the database, an
1395 1394
 :exc:`~django.db.IntegrityError` will be raised.
1396 1395
 
1397  
-Finally, a word on using ``get_or_create()`` in Django views. As mentioned
1398  
-earlier, ``get_or_create()`` is mostly useful in scripts that need to parse
1399  
-data and create new records if existing ones aren't available. But if you need
1400  
-to use ``get_or_create()`` in a view, please make sure to use it only in
1401  
-``POST`` requests unless you have a good reason not to. ``GET`` requests
1402  
-shouldn't have any effect on data; use ``POST`` whenever a request to a page
1403  
-has a side effect on your data. For more, see `Safe methods`_ in the HTTP spec.
  1396
+This method is atomic assuming correct usage, correct database configuration,
  1397
+and correct behavior of the underlying database. However, if uniqueness is not
  1398
+enforced at the database level for the ``kwargs`` used in a ``get_or_create``
  1399
+call (see :attr:`~django.db.models.Field.unique` or
  1400
+:attr:`~django.db.models.Options.unique_together`), this method is prone to a
  1401
+race-condition which can result in multiple rows with the same parameters being
  1402
+inserted simultaneously.
  1403
+
  1404
+If you are using MySQL, be sure to use the ``READ COMMITTED`` isolation level
  1405
+rather than ``REPEATABLE READ`` (the default), otherwise you may see cases
  1406
+where ``get_or_create`` will raise an :exc:`~django.db.IntegrityError` but the
  1407
+object won't appear in a subsequent :meth:`~django.db.models.query.QuerySet.get`
  1408
+call.
  1409
+
  1410
+Finally, a word on using ``get_or_create()`` in Django views: please make sure
  1411
+to use it only in ``POST`` requests unless you have a good reason not to
  1412
+``GET`` requests shouldn't have any effect on data; use ``POST`` whenever a
  1413
+request to a page as a side effect on your data. For more, see `Safe methods`_
  1414
+in the HTTP spec.
1404 1415
 
1405 1416
 .. _Safe methods: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
1406 1417
 

0 notes on commit 428de2e

Chris Jerdonek

@timgraham there should be a period after "good reason not to" (or colon if the rest of the sentence is reworked). I would also consider changing the colon and semicolon in this sentence into periods since they don't seem to add much here.

Please sign in to comment.
Something went wrong with that request. Please try again.