Skip to content

Commit

Permalink
Fixed #21410 -- Fixed prefetch_related() for FK relations with relate…
Browse files Browse the repository at this point in the history
…d_name='+'.

Regression introduced by commit 9777442.

Thanks to trac username troygrosfield for the report and test case.
  • Loading branch information
loic committed Nov 13, 2013
1 parent 3c10d1e commit e6e30aa
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 6 deletions.
12 changes: 11 additions & 1 deletion django/db/models/fields/related.py
Expand Up @@ -274,7 +274,17 @@ def get_prefetch_queryset(self, instances, queryset=None):
rel_obj_attr = self.field.get_foreign_related_value
instance_attr = self.field.get_local_related_value
instances_dict = dict((instance_attr(inst), inst) for inst in instances)
query = {'%s__in' % self.field.related_query_name(): instances}
related_field = self.field.foreign_related_fields[0]

# FIXME: This will need to be revisited when we introduce support for
# composite fields. In the meantime we take this practical approach to
# solve a regression on 1.6 when the reverse manager in hidden
# (related_name ends with a '+'). Refs #21410.
if self.field.rel.is_hidden():
query = {'%s__in' % related_field.name: set(instance_attr(inst)[0] for inst in instances)}
else:
query = {'%s__in' % self.field.related_query_name(): instances}

qs = self.get_queryset(instance=instances[0]).filter(**query)
# Since we're going to assign directly in the cache,
# we must manage the reverse relation cache manually.
Expand Down
22 changes: 18 additions & 4 deletions tests/prefetch_related/models.py
Expand Up @@ -3,8 +3,8 @@
from django.db import models
from django.utils.encoding import python_2_unicode_compatible

## Basic tests

## Basic tests

@python_2_unicode_compatible
class Author(models.Model):
Expand Down Expand Up @@ -80,8 +80,8 @@ class BookReview(models.Model):
book = models.ForeignKey(BookWithYear)
notes = models.TextField(null=True, blank=True)

## Models for default manager tests

## Models for default manager tests

class Qualification(models.Model):
name = models.CharField(max_length=10)
Expand Down Expand Up @@ -167,7 +167,6 @@ class Meta:

## Models for lookup ordering tests


class House(models.Model):
address = models.CharField(max_length=255)
owner = models.ForeignKey('Person', null=True)
Expand Down Expand Up @@ -212,7 +211,7 @@ class Meta:
ordering = ['id']


### Ticket 19607
## Ticket #19607

@python_2_unicode_compatible
class LessonEntry(models.Model):
Expand All @@ -230,3 +229,18 @@ class WordEntry(models.Model):

def __str__(self):
return "%s (%s)" % (self.name, self.id)


## Ticket #21410: Regression when related_name="+"

@python_2_unicode_compatible
class Author2(models.Model):
name = models.CharField(max_length=50, unique=True)
first_book = models.ForeignKey('Book', related_name='first_time_authors+')
favorite_books = models.ManyToManyField('Book', related_name='+')

def __str__(self):
return self.name

class Meta:
ordering = ['id']
28 changes: 27 additions & 1 deletion tests/prefetch_related/tests.py
Expand Up @@ -10,7 +10,7 @@
from .models import (Author, Book, Reader, Qualification, Teacher, Department,
TaggedItem, Bookmark, AuthorAddress, FavoriteAuthors, AuthorWithAge,
BookWithYear, BookReview, Person, House, Room, Employee, Comment,
LessonEntry, WordEntry)
LessonEntry, WordEntry, Author2)


class PrefetchRelatedTests(TestCase):
Expand Down Expand Up @@ -973,3 +973,29 @@ def setUp(self):

def test_bug(self):
list(WordEntry.objects.prefetch_related('lesson_entry', 'lesson_entry__wordentry_set'))


class Ticket21410Tests(TestCase):

def setUp(self):
self.book1 = Book.objects.create(title="Poems")
self.book2 = Book.objects.create(title="Jane Eyre")
self.book3 = Book.objects.create(title="Wuthering Heights")
self.book4 = Book.objects.create(title="Sense and Sensibility")

self.author1 = Author2.objects.create(name="Charlotte",
first_book=self.book1)
self.author2 = Author2.objects.create(name="Anne",
first_book=self.book1)
self.author3 = Author2.objects.create(name="Emily",
first_book=self.book1)
self.author4 = Author2.objects.create(name="Jane",
first_book=self.book4)

self.author1.favorite_books.add(self.book1, self.book2, self.book3)
self.author2.favorite_books.add(self.book1)
self.author3.favorite_books.add(self.book2)
self.author4.favorite_books.add(self.book3)

def test_bug(self):
list(Author2.objects.prefetch_related('first_book', 'favorite_books'))

0 comments on commit e6e30aa

Please sign in to comment.