diff options
| author | tschilling <schillingt@better-simple.com> | 2023-01-30 20:39:15 -0600 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2023-02-14 11:50:35 +0100 |
| commit | c5808470aaffda661cb911b06d5b848dd7b75467 (patch) | |
| tree | fd4e8b25bf9a7fee05cd61f27c6536a57f134a16 /tests | |
| parent | ecafcaf634fcef93f9da8cb12795273dd1c3a576 (diff) | |
Fixed #34280 -- Allowed specifying different field values for create operation in QuerySet.update_or_create().
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/async/test_async_queryset.py | 7 | ||||
| -rw-r--r-- | tests/async/test_async_related_managers.py | 12 | ||||
| -rw-r--r-- | tests/generic_relations/tests.py | 60 | ||||
| -rw-r--r-- | tests/get_or_create/models.py | 1 | ||||
| -rw-r--r-- | tests/get_or_create/tests.py | 105 |
5 files changed, 171 insertions, 14 deletions
diff --git a/tests/async/test_async_queryset.py b/tests/async/test_async_queryset.py index 253183ea10..e83157f5bd 100644 --- a/tests/async/test_async_queryset.py +++ b/tests/async/test_async_queryset.py @@ -99,10 +99,17 @@ class AsyncQuerySetTest(TestCase): id=self.s1.id, defaults={"field": 2} ) self.assertEqual(instance, self.s1) + self.assertEqual(instance.field, 2) self.assertIs(created, False) instance, created = await SimpleModel.objects.aupdate_or_create(field=4) self.assertEqual(await SimpleModel.objects.acount(), 4) self.assertIs(created, True) + instance, created = await SimpleModel.objects.aupdate_or_create( + field=5, defaults={"field": 7}, create_defaults={"field": 6} + ) + self.assertEqual(await SimpleModel.objects.acount(), 5) + self.assertIs(created, True) + self.assertEqual(instance.field, 6) @skipUnlessDBFeature("has_bulk_insert") @async_to_sync diff --git a/tests/async/test_async_related_managers.py b/tests/async/test_async_related_managers.py index c475b54899..56f86339ef 100644 --- a/tests/async/test_async_related_managers.py +++ b/tests/async/test_async_related_managers.py @@ -44,12 +44,18 @@ class AsyncRelatedManagersOperationTest(TestCase): self.assertIs(created, True) self.assertEqual(await self.mtm1.simples.acount(), 1) self.assertEqual(new_simple.field, 2) - new_simple, created = await self.mtm1.simples.aupdate_or_create( + new_simple1, created = await self.mtm1.simples.aupdate_or_create( id=new_simple.id, defaults={"field": 3} ) self.assertIs(created, False) - self.assertEqual(await self.mtm1.simples.acount(), 1) - self.assertEqual(new_simple.field, 3) + self.assertEqual(new_simple1.field, 3) + + new_simple2, created = await self.mtm1.simples.aupdate_or_create( + field=4, defaults={"field": 6}, create_defaults={"field": 5} + ) + self.assertIs(created, True) + self.assertEqual(new_simple2.field, 5) + self.assertEqual(await self.mtm1.simples.acount(), 2) async def test_aupdate_or_create_reverse(self): new_relatedmodel, created = await self.s1.relatedmodel_set.aupdate_or_create() diff --git a/tests/generic_relations/tests.py b/tests/generic_relations/tests.py index 18e3578f60..fab23dfde5 100644 --- a/tests/generic_relations/tests.py +++ b/tests/generic_relations/tests.py @@ -59,6 +59,19 @@ class GenericRelationsTests(TestCase): self.assertTrue(created) self.assertEqual(count + 1, self.bacon.tags.count()) + def test_generic_update_or_create_when_created_with_create_defaults(self): + count = self.bacon.tags.count() + tag, created = self.bacon.tags.update_or_create( + # Since, the "stinky" tag doesn't exist create + # a "juicy" tag. + create_defaults={"tag": "juicy"}, + defaults={"tag": "uncured"}, + tag="stinky", + ) + self.assertEqual(tag.tag, "juicy") + self.assertIs(created, True) + self.assertEqual(count + 1, self.bacon.tags.count()) + def test_generic_update_or_create_when_updated(self): """ Should be able to use update_or_create from the generic related manager @@ -74,6 +87,17 @@ class GenericRelationsTests(TestCase): self.assertEqual(count + 1, self.bacon.tags.count()) self.assertEqual(tag.tag, "juicy") + def test_generic_update_or_create_when_updated_with_defaults(self): + count = self.bacon.tags.count() + tag = self.bacon.tags.create(tag="stinky") + self.assertEqual(count + 1, self.bacon.tags.count()) + tag, created = self.bacon.tags.update_or_create( + create_defaults={"tag": "uncured"}, defaults={"tag": "juicy"}, id=tag.id + ) + self.assertIs(created, False) + self.assertEqual(count + 1, self.bacon.tags.count()) + self.assertEqual(tag.tag, "juicy") + async def test_generic_async_aupdate_or_create(self): tag, created = await self.bacon.tags.aupdate_or_create( id=self.fatty.id, defaults={"tag": "orange"} @@ -86,6 +110,22 @@ class GenericRelationsTests(TestCase): self.assertEqual(await self.bacon.tags.acount(), 3) self.assertEqual(tag.tag, "pink") + async def test_generic_async_aupdate_or_create_with_create_defaults(self): + tag, created = await self.bacon.tags.aupdate_or_create( + id=self.fatty.id, + create_defaults={"tag": "pink"}, + defaults={"tag": "orange"}, + ) + self.assertIs(created, False) + self.assertEqual(tag.tag, "orange") + self.assertEqual(await self.bacon.tags.acount(), 2) + tag, created = await self.bacon.tags.aupdate_or_create( + tag="pink", create_defaults={"tag": "brown"} + ) + self.assertIs(created, True) + self.assertEqual(await self.bacon.tags.acount(), 3) + self.assertEqual(tag.tag, "brown") + def test_generic_get_or_create_when_created(self): """ Should be able to use get_or_create from the generic related manager @@ -550,6 +590,26 @@ class GenericRelationsTests(TestCase): self.assertFalse(created) self.assertEqual(tag.content_object.id, diamond.id) + def test_update_or_create_defaults_with_create_defaults(self): + # update_or_create() should work with virtual fields (content_object). + quartz = Mineral.objects.create(name="Quartz", hardness=7) + diamond = Mineral.objects.create(name="Diamond", hardness=7) + tag, created = TaggedItem.objects.update_or_create( + tag="shiny", + create_defaults={"content_object": quartz}, + defaults={"content_object": diamond}, + ) + self.assertIs(created, True) + self.assertEqual(tag.content_object.id, quartz.id) + + tag, created = TaggedItem.objects.update_or_create( + tag="shiny", + create_defaults={"content_object": quartz}, + defaults={"content_object": diamond}, + ) + self.assertIs(created, False) + self.assertEqual(tag.content_object.id, diamond.id) + def test_query_content_type(self): msg = "Field 'content_object' does not generate an automatic reverse relation" with self.assertRaisesMessage(FieldError, msg): diff --git a/tests/get_or_create/models.py b/tests/get_or_create/models.py index 6875671501..c5ba90a231 100644 --- a/tests/get_or_create/models.py +++ b/tests/get_or_create/models.py @@ -6,6 +6,7 @@ class Person(models.Model): last_name = models.CharField(max_length=100) birthday = models.DateField() defaults = models.TextField() + create_defaults = models.TextField() class DefaultPerson(models.Model): diff --git a/tests/get_or_create/tests.py b/tests/get_or_create/tests.py index c3a3fb0e11..0b56d6b1a2 100644 --- a/tests/get_or_create/tests.py +++ b/tests/get_or_create/tests.py @@ -330,15 +330,24 @@ class UpdateOrCreateTests(TestCase): self.assertEqual(p.birthday, date(1940, 10, 10)) def test_create_twice(self): - params = { - "first_name": "John", - "last_name": "Lennon", - "birthday": date(1940, 10, 10), - } - Person.objects.update_or_create(**params) - # If we execute the exact same statement, it won't create a Person. - p, created = Person.objects.update_or_create(**params) - self.assertFalse(created) + p, created = Person.objects.update_or_create( + first_name="John", + last_name="Lennon", + create_defaults={"birthday": date(1940, 10, 10)}, + defaults={"birthday": date(1950, 2, 2)}, + ) + self.assertIs(created, True) + self.assertEqual(p.birthday, date(1940, 10, 10)) + # If we execute the exact same statement, it won't create a Person, but + # will update the birthday. + p, created = Person.objects.update_or_create( + first_name="John", + last_name="Lennon", + create_defaults={"birthday": date(1940, 10, 10)}, + defaults={"birthday": date(1950, 2, 2)}, + ) + self.assertIs(created, False) + self.assertEqual(p.birthday, date(1950, 2, 2)) def test_integrity(self): """ @@ -391,8 +400,14 @@ class UpdateOrCreateTests(TestCase): """ p = Publisher.objects.create(name="Acme Publishing") book, created = p.books.update_or_create(name="The Book of Ed & Fred") - self.assertTrue(created) + self.assertIs(created, True) self.assertEqual(p.books.count(), 1) + book, created = p.books.update_or_create( + name="Basics of Django", create_defaults={"name": "Advanced Django"} + ) + self.assertIs(created, True) + self.assertEqual(book.name, "Advanced Django") + self.assertEqual(p.books.count(), 2) def test_update_with_related_manager(self): """ @@ -406,6 +421,14 @@ class UpdateOrCreateTests(TestCase): book, created = p.books.update_or_create(defaults={"name": name}, id=book.id) self.assertFalse(created) self.assertEqual(book.name, name) + # create_defaults should be ignored. + book, created = p.books.update_or_create( + create_defaults={"name": "Basics of Django"}, + defaults={"name": name}, + id=book.id, + ) + self.assertIs(created, False) + self.assertEqual(book.name, name) self.assertEqual(p.books.count(), 1) def test_create_with_many(self): @@ -418,8 +441,16 @@ class UpdateOrCreateTests(TestCase): book, created = author.books.update_or_create( name="The Book of Ed & Fred", publisher=p ) - self.assertTrue(created) + self.assertIs(created, True) self.assertEqual(author.books.count(), 1) + book, created = author.books.update_or_create( + name="Basics of Django", + publisher=p, + create_defaults={"name": "Advanced Django"}, + ) + self.assertIs(created, True) + self.assertEqual(book.name, "Advanced Django") + self.assertEqual(author.books.count(), 2) def test_update_with_many(self): """ @@ -437,6 +468,14 @@ class UpdateOrCreateTests(TestCase): ) self.assertFalse(created) self.assertEqual(book.name, name) + # create_defaults should be ignored. + book, created = author.books.update_or_create( + create_defaults={"name": "Basics of Django"}, + defaults={"name": name}, + id=book.id, + ) + self.assertIs(created, False) + self.assertEqual(book.name, name) self.assertEqual(author.books.count(), 1) def test_defaults_exact(self): @@ -467,6 +506,34 @@ class UpdateOrCreateTests(TestCase): self.assertFalse(created) self.assertEqual(obj.defaults, "another testing") + def test_create_defaults_exact(self): + """ + If you have a field named create_defaults and want to use it as an + exact lookup, you need to use 'create_defaults__exact'. + """ + obj, created = Person.objects.update_or_create( + first_name="George", + last_name="Harrison", + create_defaults__exact="testing", + create_defaults={ + "birthday": date(1943, 2, 25), + "create_defaults": "testing", + }, + ) + self.assertIs(created, True) + self.assertEqual(obj.create_defaults, "testing") + obj, created = Person.objects.update_or_create( + first_name="George", + last_name="Harrison", + create_defaults__exact="testing", + create_defaults={ + "birthday": date(1943, 2, 25), + "create_defaults": "another testing", + }, + ) + self.assertIs(created, False) + self.assertEqual(obj.create_defaults, "testing") + def test_create_callable_default(self): obj, created = Person.objects.update_or_create( first_name="George", @@ -476,6 +543,16 @@ class UpdateOrCreateTests(TestCase): self.assertIs(created, True) self.assertEqual(obj.birthday, date(1943, 2, 25)) + def test_create_callable_create_defaults(self): + obj, created = Person.objects.update_or_create( + first_name="George", + last_name="Harrison", + defaults={}, + create_defaults={"birthday": lambda: date(1943, 2, 25)}, + ) + self.assertIs(created, True) + self.assertEqual(obj.birthday, date(1943, 2, 25)) + def test_update_callable_default(self): Person.objects.update_or_create( first_name="George", @@ -694,6 +771,12 @@ class InvalidCreateArgumentsTests(TransactionTestCase): with self.assertRaisesMessage(FieldError, self.msg): Thing.objects.update_or_create(name="a", defaults={"nonexistent": "b"}) + def test_update_or_create_with_invalid_create_defaults(self): + with self.assertRaisesMessage(FieldError, self.msg): + Thing.objects.update_or_create( + name="a", create_defaults={"nonexistent": "b"} + ) + def test_update_or_create_with_invalid_kwargs(self): with self.assertRaisesMessage(FieldError, self.bad_field_msg): Thing.objects.update_or_create(name="a", nonexistent="b") |
