mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Fixed #30199 -- Adjusted QuerySet.get_or_create() docs to highlight atomicity warning.
This commit is contained in:
parent
de4832c49b
commit
1686dce06c
1
AUTHORS
1
AUTHORS
@ -38,6 +38,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Alexander Dutton <dev@alexdutton.co.uk>
|
Alexander Dutton <dev@alexdutton.co.uk>
|
||||||
Alexander Myodov <alex@myodov.com>
|
Alexander Myodov <alex@myodov.com>
|
||||||
Alexandr Tatarinov <tatarinov1997@gmail.com>
|
Alexandr Tatarinov <tatarinov1997@gmail.com>
|
||||||
|
Alex Becker <https://alexcbecker.net/>
|
||||||
Alex Couper <http://alexcouper.com/>
|
Alex Couper <http://alexcouper.com/>
|
||||||
Alex Dedul
|
Alex Dedul
|
||||||
Alex Gaynor <alex.gaynor@gmail.com>
|
Alex Gaynor <alex.gaynor@gmail.com>
|
||||||
|
@ -488,7 +488,10 @@ this entry are the four standard isolation levels:
|
|||||||
|
|
||||||
or ``None`` to use the server's configured isolation level. However, Django
|
or ``None`` to use the server's configured isolation level. However, Django
|
||||||
works best with and defaults to read committed rather than MySQL's default,
|
works best with and defaults to read committed rather than MySQL's default,
|
||||||
repeatable read. Data loss is possible with repeatable read.
|
repeatable read. Data loss is possible with repeatable read. In particular,
|
||||||
|
you may see cases where :meth:`~django.db.models.query.QuerySet.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.
|
||||||
|
|
||||||
.. _transaction isolation level: https://dev.mysql.com/doc/refman/en/innodb-transaction-isolation-levels.html
|
.. _transaction isolation level: https://dev.mysql.com/doc/refman/en/innodb-transaction-isolation-levels.html
|
||||||
|
|
||||||
|
@ -1879,7 +1879,8 @@ 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 object and ``created`` is a boolean specifying whether a new object was
|
||||||
created.
|
created.
|
||||||
|
|
||||||
This is meant as a shortcut to boilerplatish code. For example::
|
This is meant to prevent duplicate objects from being created when requests are
|
||||||
|
made in parallel, and as a shortcut to boilerplatish code. For example::
|
||||||
|
|
||||||
try:
|
try:
|
||||||
obj = Person.objects.get(first_name='John', last_name='Lennon')
|
obj = Person.objects.get(first_name='John', last_name='Lennon')
|
||||||
@ -1887,8 +1888,9 @@ This is meant as a shortcut to boilerplatish code. For example::
|
|||||||
obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
|
obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
|
||||||
obj.save()
|
obj.save()
|
||||||
|
|
||||||
This pattern gets quite unwieldy as the number of fields in a model goes up.
|
Here, with concurrent requests, multiple attempts to save a ``Person`` with
|
||||||
The above example can be rewritten using ``get_or_create()`` like so::
|
the same parameters may be made. To avoid this race condition, the above
|
||||||
|
example can be rewritten using ``get_or_create()`` like so::
|
||||||
|
|
||||||
obj, created = Person.objects.get_or_create(
|
obj, created = Person.objects.get_or_create(
|
||||||
first_name='John',
|
first_name='John',
|
||||||
@ -1900,6 +1902,15 @@ Any keyword arguments passed to ``get_or_create()`` — *except* an optional one
|
|||||||
called ``defaults`` — will be used in a :meth:`get()` call. If an object is
|
called ``defaults`` — will be used in a :meth:`get()` call. If an object is
|
||||||
found, ``get_or_create()`` returns a tuple of that object and ``False``.
|
found, ``get_or_create()`` returns a tuple of that object and ``False``.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
This method is atomic assuming that the database enforces uniqueness of the
|
||||||
|
keyword arguments (see :attr:`~django.db.models.Field.unique` or
|
||||||
|
:attr:`~django.db.models.Options.unique_together`). If the fields used in the
|
||||||
|
keyword arguments do not have a uniqueness constraint, concurrent calls to
|
||||||
|
this method may result in multiple rows with the same parameters being
|
||||||
|
inserted.
|
||||||
|
|
||||||
You can specify more complex conditions for the retrieved object by chaining
|
You can specify more complex conditions for the retrieved object by chaining
|
||||||
``get_or_create()`` with ``filter()`` and using :class:`Q objects
|
``get_or_create()`` with ``filter()`` and using :class:`Q objects
|
||||||
<django.db.models.Q>`. For example, to retrieve Robert or Bob Marley if either
|
<django.db.models.Q>`. For example, to retrieve Robert or Bob Marley if either
|
||||||
@ -1941,20 +1952,6 @@ when you're using manually specified primary keys. If an object needs to be
|
|||||||
created and the key already exists in the database, an
|
created and the key already exists in the database, an
|
||||||
:exc:`~django.db.IntegrityError` will be raised.
|
:exc:`~django.db.IntegrityError` will be raised.
|
||||||
|
|
||||||
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
|
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.
|
to use it only in ``POST`` requests unless you have a good reason not to.
|
||||||
``GET`` requests shouldn't have any effect on data. Instead, use ``POST``
|
``GET`` requests shouldn't have any effect on data. Instead, use ``POST``
|
||||||
|
Loading…
Reference in New Issue
Block a user