Loading django/db/models/query.py +1 −0 Original line number Diff line number Diff line Loading @@ -500,6 +500,7 @@ class QuerySet(object): """ try: with transaction.atomic(using=self.db): params = {k: v() if callable(v) else v for k, v in params.items()} obj = self.create(**params) return obj, True except IntegrityError: Loading docs/ref/models/querysets.txt +15 −7 Original line number Diff line number Diff line Loading @@ -1687,18 +1687,18 @@ tuple of the new object and ``True``. The new object will be created roughly according to this algorithm:: params = {k: v for k, v in kwargs.items() if '__' not in k} params.update(defaults) params.update(({k: v() if callable(v) else v for k, v in defaults.items()}) obj = self.model(**params) obj.save() In English, that means start with any non-``'defaults'`` keyword argument that doesn't contain a double underscore (which would indicate a non-exact lookup). Then add the contents of ``defaults``, overriding any keys if necessary, and use the result as the keyword arguments to the model class. As hinted at above, this is a simplification of the algorithm that is used, but it contains all the pertinent details. The internal implementation has some more error-checking than this and handles some extra edge-conditions; if you're interested, read the code. use the result as the keyword arguments to the model class. If there are any callables in ``defaults``, evaluate them. As hinted at above, this is a simplification of the algorithm that is used, but it contains all the pertinent details. The internal implementation has some more error-checking than this and handles some extra edge-conditions; if you're interested, read the code. If you have a field named ``defaults`` and want to use it as an exact lookup in ``get_or_create()``, just use ``'defaults__exact'``, like so:: Loading Loading @@ -1764,6 +1764,10 @@ whenever a request to a page has a side effect on your data. For more, see chapter because it isn't related to that book, but it can't create it either because ``title`` field should be unique. .. versionchanged:: 1.11 Added support for callable values in ``defaults``. ``update_or_create()`` ~~~~~~~~~~~~~~~~~~~~~~ Loading @@ -1771,7 +1775,7 @@ whenever a request to a page has a side effect on your data. For more, see A convenience method for updating an object with the given ``kwargs``, creating a new one if necessary. The ``defaults`` is a dictionary of (field, value) pairs used to update the object. pairs used to update the object. The values in ``defaults`` can be callables. Returns a tuple of ``(object, created)``, where ``object`` is the created or updated object and ``created`` is a boolean specifying whether a new object was Loading Loading @@ -1806,6 +1810,10 @@ As described above in :meth:`get_or_create`, this method is prone to a race-condition which can result in multiple rows being inserted simultaneously if uniqueness is not enforced at the database level. .. versionchanged:: 1.11 Added support for callable values in ``defaults``. ``bulk_create()`` ~~~~~~~~~~~~~~~~~ Loading docs/releases/1.11.txt +4 −1 Original line number Diff line number Diff line Loading @@ -175,7 +175,10 @@ Migrations Models ~~~~~~ * ... * Added support for callable values in the ``defaults`` argument of :meth:`QuerySet.update_or_create() <django.db.models.query.QuerySet.update_or_create>` and :meth:`~django.db.models.query.QuerySet.get_or_create`. Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ Loading tests/get_or_create/tests.py +26 −0 Original line number Diff line number Diff line Loading @@ -146,6 +146,25 @@ class GetOrCreateTests(TestCase): self.assertFalse(created) self.assertEqual(obj, obj2) def test_callable_defaults(self): """ Callables in `defaults` are evaluated if the instance is created. """ obj, created = Person.objects.get_or_create( first_name="George", defaults={"last_name": "Harrison", "birthday": lambda: date(1943, 2, 25)}, ) self.assertTrue(created) self.assertEqual(date(1943, 2, 25), obj.birthday) def test_callable_defaults_not_called(self): def raise_exception(): raise AssertionError obj, created = Person.objects.get_or_create( first_name="John", last_name="Lennon", defaults={"birthday": lambda: raise_exception()}, ) class GetOrCreateTestsWithManualPKs(TestCase): Loading Loading @@ -387,3 +406,10 @@ class UpdateOrCreateTests(TestCase): ) self.assertFalse(created) self.assertEqual(obj.defaults, 'another testing') def test_update_callable_default(self): obj, created = Person.objects.update_or_create( first_name='George', last_name='Harrison', defaults={'birthday': lambda: date(1943, 2, 25)}, ) self.assertEqual(obj.birthday, date(1943, 2, 25)) Loading
django/db/models/query.py +1 −0 Original line number Diff line number Diff line Loading @@ -500,6 +500,7 @@ class QuerySet(object): """ try: with transaction.atomic(using=self.db): params = {k: v() if callable(v) else v for k, v in params.items()} obj = self.create(**params) return obj, True except IntegrityError: Loading
docs/ref/models/querysets.txt +15 −7 Original line number Diff line number Diff line Loading @@ -1687,18 +1687,18 @@ tuple of the new object and ``True``. The new object will be created roughly according to this algorithm:: params = {k: v for k, v in kwargs.items() if '__' not in k} params.update(defaults) params.update(({k: v() if callable(v) else v for k, v in defaults.items()}) obj = self.model(**params) obj.save() In English, that means start with any non-``'defaults'`` keyword argument that doesn't contain a double underscore (which would indicate a non-exact lookup). Then add the contents of ``defaults``, overriding any keys if necessary, and use the result as the keyword arguments to the model class. As hinted at above, this is a simplification of the algorithm that is used, but it contains all the pertinent details. The internal implementation has some more error-checking than this and handles some extra edge-conditions; if you're interested, read the code. use the result as the keyword arguments to the model class. If there are any callables in ``defaults``, evaluate them. As hinted at above, this is a simplification of the algorithm that is used, but it contains all the pertinent details. The internal implementation has some more error-checking than this and handles some extra edge-conditions; if you're interested, read the code. If you have a field named ``defaults`` and want to use it as an exact lookup in ``get_or_create()``, just use ``'defaults__exact'``, like so:: Loading Loading @@ -1764,6 +1764,10 @@ whenever a request to a page has a side effect on your data. For more, see chapter because it isn't related to that book, but it can't create it either because ``title`` field should be unique. .. versionchanged:: 1.11 Added support for callable values in ``defaults``. ``update_or_create()`` ~~~~~~~~~~~~~~~~~~~~~~ Loading @@ -1771,7 +1775,7 @@ whenever a request to a page has a side effect on your data. For more, see A convenience method for updating an object with the given ``kwargs``, creating a new one if necessary. The ``defaults`` is a dictionary of (field, value) pairs used to update the object. pairs used to update the object. The values in ``defaults`` can be callables. Returns a tuple of ``(object, created)``, where ``object`` is the created or updated object and ``created`` is a boolean specifying whether a new object was Loading Loading @@ -1806,6 +1810,10 @@ As described above in :meth:`get_or_create`, this method is prone to a race-condition which can result in multiple rows being inserted simultaneously if uniqueness is not enforced at the database level. .. versionchanged:: 1.11 Added support for callable values in ``defaults``. ``bulk_create()`` ~~~~~~~~~~~~~~~~~ Loading
docs/releases/1.11.txt +4 −1 Original line number Diff line number Diff line Loading @@ -175,7 +175,10 @@ Migrations Models ~~~~~~ * ... * Added support for callable values in the ``defaults`` argument of :meth:`QuerySet.update_or_create() <django.db.models.query.QuerySet.update_or_create>` and :meth:`~django.db.models.query.QuerySet.get_or_create`. Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ Loading
tests/get_or_create/tests.py +26 −0 Original line number Diff line number Diff line Loading @@ -146,6 +146,25 @@ class GetOrCreateTests(TestCase): self.assertFalse(created) self.assertEqual(obj, obj2) def test_callable_defaults(self): """ Callables in `defaults` are evaluated if the instance is created. """ obj, created = Person.objects.get_or_create( first_name="George", defaults={"last_name": "Harrison", "birthday": lambda: date(1943, 2, 25)}, ) self.assertTrue(created) self.assertEqual(date(1943, 2, 25), obj.birthday) def test_callable_defaults_not_called(self): def raise_exception(): raise AssertionError obj, created = Person.objects.get_or_create( first_name="John", last_name="Lennon", defaults={"birthday": lambda: raise_exception()}, ) class GetOrCreateTestsWithManualPKs(TestCase): Loading Loading @@ -387,3 +406,10 @@ class UpdateOrCreateTests(TestCase): ) self.assertFalse(created) self.assertEqual(obj.defaults, 'another testing') def test_update_callable_default(self): obj, created = Person.objects.update_or_create( first_name='George', last_name='Harrison', defaults={'birthday': lambda: date(1943, 2, 25)}, ) self.assertEqual(obj.birthday, date(1943, 2, 25))