summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian King <brian@liip.ch>2015-06-05 12:40:51 +0100
committerTim Graham <timograham@gmail.com>2015-06-15 09:37:38 -0400
commitbfb5b7150ff52571a7a3cf10e0dd0d1dbd45c4b5 (patch)
tree6ad940d20c235e2647e8188c608c061a8770bba0
parent841a87785a78cc37362a66856025bae2f7ba633c (diff)
Fixed #24912 -- Fixed prefetch_related failure for UUIDField primary keys
This resolves a problem on databases besides PostgreSQL when using prefetch_related with a source model that uses a UUID primary key.
-rw-r--r--django/db/models/fields/related.py5
-rw-r--r--docs/releases/1.8.3.txt3
-rw-r--r--tests/prefetch_related/models.py17
-rw-r--r--tests/prefetch_related/test_uuid.py95
4 files changed, 119 insertions, 1 deletions
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index a3183b331f..59b8dc1329 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -1002,7 +1002,10 @@ def create_many_related_manager(superclass, rel, reverse):
getattr(result, '_prefetch_related_val_%s' % f.attname)
for f in fk.local_related_fields
),
- lambda inst: tuple(getattr(inst, f.attname) for f in fk.foreign_related_fields),
+ lambda inst: tuple(
+ f.get_db_prep_value(getattr(inst, f.attname), connection)
+ for f in fk.foreign_related_fields
+ ),
False,
self.prefetch_cache_name,
)
diff --git a/docs/releases/1.8.3.txt b/docs/releases/1.8.3.txt
index d7e063b397..39e08f904c 100644
--- a/docs/releases/1.8.3.txt
+++ b/docs/releases/1.8.3.txt
@@ -66,3 +66,6 @@ Bugfixes
* Provided better backwards compatibility for the ``verbosity`` argument in
``optparse`` management commands by casting it to an integer
(:ticket:`24769`).
+
+* Fixed ``prefetch_related()`` on databases other than PostgreSQL for models
+ using UUID primary keys (:ticket:`24912`).
diff --git a/tests/prefetch_related/models.py b/tests/prefetch_related/models.py
index bfc0ae0217..207f12a11a 100644
--- a/tests/prefetch_related/models.py
+++ b/tests/prefetch_related/models.py
@@ -1,3 +1,5 @@
+import uuid
+
from django.contrib.contenttypes.fields import (
GenericForeignKey, GenericRelation,
)
@@ -257,3 +259,18 @@ class Author2(models.Model):
class Meta:
ordering = ['id']
+
+
+# Models for many-to-many with UUID pk test:
+
+class Pet(models.Model):
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
+ name = models.CharField(max_length=20)
+ people = models.ManyToManyField(Person, related_name='pets')
+
+
+class Flea(models.Model):
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
+ current_room = models.ForeignKey(Room, related_name='fleas', null=True)
+ pets_visited = models.ManyToManyField(Pet, related_name='fleas_hosted')
+ people_visited = models.ManyToManyField(Person, related_name='fleas_hosted')
diff --git a/tests/prefetch_related/test_uuid.py b/tests/prefetch_related/test_uuid.py
new file mode 100644
index 0000000000..8d885e1057
--- /dev/null
+++ b/tests/prefetch_related/test_uuid.py
@@ -0,0 +1,95 @@
+from __future__ import unicode_literals
+
+from django.test import TestCase
+
+from .models import Flea, House, Person, Pet, Room
+
+
+class UUIDPrefetchRelated(TestCase):
+
+ def test_prefetch_related_from_uuid_model(self):
+ Pet.objects.create(name='Fifi').people.add(
+ Person.objects.create(name='Ellen'),
+ Person.objects.create(name='George'),
+ )
+
+ with self.assertNumQueries(2):
+ pet = Pet.objects.prefetch_related('people').get(name='Fifi')
+ with self.assertNumQueries(0):
+ self.assertEqual(2, len(pet.people.all()))
+
+ def test_prefetch_related_to_uuid_model(self):
+ Person.objects.create(name='Bella').pets.add(
+ Pet.objects.create(name='Socks'),
+ Pet.objects.create(name='Coffee'),
+ )
+
+ with self.assertNumQueries(2):
+ person = Person.objects.prefetch_related('pets').get(name='Bella')
+ with self.assertNumQueries(0):
+ self.assertEqual(2, len(person.pets.all()))
+
+ def test_prefetch_related_from_uuid_model_to_uuid_model(self):
+ fleas = [Flea.objects.create() for i in range(3)]
+ Pet.objects.create(name='Fifi').fleas_hosted.add(*fleas)
+ Pet.objects.create(name='Bobo').fleas_hosted.add(*fleas)
+
+ with self.assertNumQueries(2):
+ pet = Pet.objects.prefetch_related('fleas_hosted').get(name='Fifi')
+ with self.assertNumQueries(0):
+ self.assertEqual(3, len(pet.fleas_hosted.all()))
+
+ with self.assertNumQueries(2):
+ flea = Flea.objects.prefetch_related('pets_visited').get(pk=fleas[0].pk)
+ with self.assertNumQueries(0):
+ self.assertEqual(2, len(flea.pets_visited.all()))
+
+
+class UUIDPrefetchRelatedLookups(TestCase):
+
+ @classmethod
+ def setUpTestData(cls):
+ house = House.objects.create(name='Redwood', address='Arcata')
+ room = Room.objects.create(name='Racoon', house=house)
+ fleas = [Flea.objects.create(current_room=room) for i in range(3)]
+ pet = Pet.objects.create(name='Spooky')
+ pet.fleas_hosted.add(*fleas)
+ person = Person.objects.create(name='Bob')
+ person.houses.add(house)
+ person.pets.add(pet)
+ person.fleas_hosted.add(*fleas)
+
+ def test_from_uuid_pk_lookup_uuid_pk_integer_pk(self):
+ # From uuid-pk model, prefetch <uuid-pk model>.<integer-pk model>:
+ with self.assertNumQueries(4):
+ spooky = Pet.objects.prefetch_related('fleas_hosted__current_room__house').get(name='Spooky')
+ with self.assertNumQueries(0):
+ self.assertEqual('Racoon', spooky.fleas_hosted.all()[0].current_room.name)
+
+ def test_from_uuid_pk_lookup_integer_pk2_uuid_pk2(self):
+ # From uuid-pk model, prefetch <integer-pk model>.<integer-pk model>.<uuid-pk model>.<uuid-pk model>:
+ with self.assertNumQueries(5):
+ spooky = Pet.objects.prefetch_related('people__houses__rooms__fleas').get(name='Spooky')
+ with self.assertNumQueries(0):
+ self.assertEqual(3, len(spooky.people.all()[0].houses.all()[0].rooms.all()[0].fleas.all()))
+
+ def test_from_integer_pk_lookup_uuid_pk_integer_pk(self):
+ # From integer-pk model, prefetch <uuid-pk model>.<integer-pk model>:
+ with self.assertNumQueries(3):
+ racoon = Room.objects.prefetch_related('fleas__people_visited').get(name='Racoon')
+ with self.assertNumQueries(0):
+ self.assertEqual('Bob', racoon.fleas.all()[0].people_visited.all()[0].name)
+
+ def test_from_integer_pk_lookup_integer_pk_uuid_pk(self):
+ # From integer-pk model, prefetch <integer-pk model>.<uuid-pk model>:
+ with self.assertNumQueries(3):
+ redwood = House.objects.prefetch_related('rooms__fleas').get(name='Redwood')
+ with self.assertNumQueries(0):
+ self.assertEqual(3, len(redwood.rooms.all()[0].fleas.all()))
+
+ def test_from_integer_pk_lookup_integer_pk_uuid_pk_uuid_pk(self):
+ # From integer-pk model, prefetch <integer-pk model>.<uuid-pk model>.<uuid-pk model>:
+ with self.assertNumQueries(4):
+ redwood = House.objects.prefetch_related('rooms__fleas__pets_visited').get(name='Redwood')
+ with self.assertNumQueries(0):
+ self.assertEqual('Spooky', redwood.rooms.all()[0].fleas.all()[0].pets_visited.all()[0].name)