#34523: update_or_create not work in parallel insertion
-------------------------------------+-------------------------------------
Reporter: gatello-s | Owner: nobody
Type: Bug | Status: closed
Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution: needsinfo
Keywords: update_or_create | Triage Stage:
TransactionManagementError | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by gatello-s):
code from db/models/query.py
{{{
return self.create(**params), True
}}}
** # test generate IntegrityError, this ok**
{{{
return self.get(**kwargs), False
}}}
** # this must work fine, but raise
django.db.transaction.TransactionManagementError**
{{{
def get_or_create(self, defaults=None, **kwargs):
"""
Look up an object with the given kwargs, creating one if
necessary.
Return a tuple of (object, created), where created is a boolean
specifying whether an object was created.
"""
# The get() needs to be targeted at the write database in order
# to avoid potential transaction consistency problems.
self._for_write = True
try:
return self.get(**kwargs), False
except self.model.DoesNotExist:
params = self._extract_model_params(defaults, **kwargs)
# Try to create an object using passed params.
try:
with transaction.atomic(using=self.db):
params = dict(resolve_callables(params))
return self.create(**params), True # test generate
IntegrityError, this ok
except IntegrityError:
try:
return self.get(**kwargs), False # this must work
fine, but raise django.db.transaction.TransactionManagementError
except self.model.DoesNotExist:
pass
raise
}}}
----
{{{
ERROR: test_update_or_create (polls.tests.TransactionManagementErrorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/query.py", line 916, in get_or_create
return self.get(**kwargs), False
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/query.py", line 637, in get
raise self.model.DoesNotExist(
polls.tests.TransactionManagementErrorTest.TestModel.DoesNotExist:
TestModel matching query does not exist.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/backends/mysql/base.py", line 75, in execute
return self.cursor.execute(query, args)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/MySQLdb/cursors.py", line 206, in execute
res = self._query(query)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/MySQLdb/cursors.py", line 320, in _query
self._do_get_result(db)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/MySQLdb/cursors.py", line 145, in _do_get_result
self._result = result = self._get_result()
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/MySQLdb/cursors.py", line 352, in _get_result
return self._get_db().store_result()
MySQLdb.IntegrityError: (1062, "Duplicate entry '1' for key 'PRIMARY'")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/query.py", line 923, in get_or_create
return self.create(**params), True
File
"/home/alex/workspace/test_TransactionManagementError/mysite/polls/tests.py",
line 19, in create
return super().create(**kwargs)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/query.py", line 658, in create
obj.save(force_insert=True, using=self.db)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/base.py", line 814, in save
self.save_base(
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/base.py", line 877, in save_base
updated = self._save_table(
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/base.py", line 1020, in _save_table
results = self._do_insert(
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/base.py", line 1061, in _do_insert
return manager._insert(
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/query.py", line 1805, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/sql/compiler.py", line 1820, in
execute_sql
cursor.execute(sql, params)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/backends/utils.py", line 67, in execute
return self._execute_with_wrappers(
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/backends/utils.py", line 80, in
_execute_with_wrappers
return executor(sql, params, many, context)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/utils.py", line 91, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/backends/mysql/base.py", line 75, in execute
return self.cursor.execute(query, args)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/MySQLdb/cursors.py", line 206, in execute
res = self._query(query)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/MySQLdb/cursors.py", line 320, in _query
self._do_get_result(db)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/MySQLdb/cursors.py", line 145, in _do_get_result
self._result = result = self._get_result()
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/MySQLdb/cursors.py", line 352, in _get_result
return self._get_db().store_result()
django.db.utils.IntegrityError: (1062, "Duplicate entry '1' for key
'PRIMARY'")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File
"/home/alex/workspace/test_TransactionManagementError/mysite/polls/tests.py",
line 47, in test_update_or_create
self.TestModel.objects.update_or_create(id=1, defaults={'field': 2})
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/query.py", line 949, in update_or_create
obj, created = self.select_for_update().get_or_create(defaults,
**kwargs)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/query.py", line 926, in get_or_create
return self.get(**kwargs), False
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/query.py", line 633, in get
num = len(clone)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/query.py", line 380, in __len__
self._fetch_all()
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/query.py", line 1881, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/query.py", line 91, in __iter__
results = compiler.execute_sql(
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/models/sql/compiler.py", line 1560, in
execute_sql
cursor.execute(sql, params)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/backends/utils.py", line 67, in execute
return self._execute_with_wrappers(
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/backends/utils.py", line 80, in
_execute_with_wrappers
return executor(sql, params, many, context)
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/backends/utils.py", line 83, in _execute
self.db.validate_no_broken_transaction()
File
"/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
/site-packages/django/db/backends/base/base.py", line 531, in
validate_no_broken_transaction
raise TransactionManagementError(
django.db.transaction.TransactionManagementError: An error occurred in the
current transaction. You can't execute queries until the end of the
'atomic' block.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/34523#comment:7>
Django <https://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 unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/01070187c31fac50-26e7d888-7fa1-48e0-bf25-0baf33cf27e1-000000%40eu-central-1.amazonses.com.