threads = list() for _ inrange(10): threads.append(threading.Thread(target=get_or_create)) for t in threads: t.start() for t in threads: t.join() self.assertNotEqual(Race.objects.count(), 1)
$ python manage.py test ... Exception in thread Thread-7: Traceback (most recent call last): File "/Users/jtr109/.pyenv/versions/3.7.4/lib/python3.7/threading.py", line 926, in _bootstrap_inner self.run() File "/Users/jtr109/.pyenv/versions/3.7.4/lib/python3.7/threading.py", line 870, in run self._target(*self._args, **self._kwargs) File "/Users/jtr109/mystuff/learn/django-update-or-create-example/race/tests.py", line 20, in get_or_create defaults=dict(name='foo', age=1), File "/Users/jtr109/mystuff/learn/django-update-or-create-example/venv/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "/Users/jtr109/mystuff/learn/django-update-or-create-example/venv/lib/python3.7/site-packages/django/db/models/query.py", line 538, in get_or_create return self.get(**kwargs), False File "/Users/jtr109/mystuff/learn/django-update-or-create-example/venv/lib/python3.7/site-packages/django/db/models/query.py", line 412, in get (self.model._meta.object_name, num) race.models.Race.MultipleObjectsReturned: get() returned more than one Race -- it returned 2!
Exception in thread Thread-9: Traceback (most recent call last): File "/Users/jtr109/.pyenv/versions/3.7.4/lib/python3.7/threading.py", line 926, in _bootstrap_inner self.run() File "/Users/jtr109/.pyenv/versions/3.7.4/lib/python3.7/threading.py", line 870, in run self._target(*self._args, **self._kwargs) File "/Users/jtr109/mystuff/learn/django-update-or-create-example/race/tests.py", line 20, in get_or_create defaults=dict(name='foo', age=1), File "/Users/jtr109/mystuff/learn/django-update-or-create-example/venv/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "/Users/jtr109/mystuff/learn/django-update-or-create-example/venv/lib/python3.7/site-packages/django/db/models/query.py", line 538, in get_or_create return self.get(**kwargs), False File "/Users/jtr109/mystuff/learn/django-update-or-create-example/venv/lib/python3.7/site-packages/django/db/models/query.py", line 412, in get (self.model._meta.object_name, num) race.models.Race.MultipleObjectsReturned: get() returned more than one Race -- it returned 2!
. ---------------------------------------------------------------------- Ran 1 test in 0.107s
OK Destroying test database for alias 'default'...
defget_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) return self._create_object_from_params(kwargs, params)
This method is atomic assuming that the database enforces uniqueness of the keyword arguments (see unique or 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.