Loading django/db/models/fields/related.py +4 −1 Original line number Diff line number Diff line Loading @@ -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, ) Loading docs/releases/1.8.3.txt +3 −0 Original line number Diff line number Diff line Loading @@ -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`). tests/prefetch_related/models.py +17 −0 Original line number Diff line number Diff line import uuid from django.contrib.contenttypes.fields import ( GenericForeignKey, GenericRelation, ) Loading Loading @@ -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') tests/prefetch_related/test_uuid.py 0 → 100644 +95 −0 Original line number Diff line number Diff line 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) Loading
django/db/models/fields/related.py +4 −1 Original line number Diff line number Diff line Loading @@ -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, ) Loading
docs/releases/1.8.3.txt +3 −0 Original line number Diff line number Diff line Loading @@ -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`).
tests/prefetch_related/models.py +17 −0 Original line number Diff line number Diff line import uuid from django.contrib.contenttypes.fields import ( GenericForeignKey, GenericRelation, ) Loading Loading @@ -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')
tests/prefetch_related/test_uuid.py 0 → 100644 +95 −0 Original line number Diff line number Diff line 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)