summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorcan <cansarigol@derinbilgi.com.tr>2019-05-29 20:24:37 +0300
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-05-31 18:11:55 +0200
commitdffa3e1992562ba60512d96d1eb5859ffff2ceb5 (patch)
treece66a812bfa12e19e738bf105b62dbfdef7a2335 /django
parentf66021f3f773023d0c61d2537d5dd1e5e1740537 (diff)
Fixed #30493 -- Fixed prefetch_related() for GenericRelation with different content types.
Co-Authored-By: Mariusz Felisiak <felisiak.mariusz@gmail.com> Thanks Simon Charette for the review.
Diffstat (limited to 'django')
-rw-r--r--django/contrib/contenttypes/fields.py29
1 files changed, 20 insertions, 9 deletions
diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py
index 62284e980e..4015f16c6b 100644
--- a/django/contrib/contenttypes/fields.py
+++ b/django/contrib/contenttypes/fields.py
@@ -1,4 +1,6 @@
import functools
+import itertools
+import operator
from collections import defaultdict
from django.contrib.contenttypes.models import ContentType
@@ -566,19 +568,28 @@ def create_generic_related_manager(superclass, rel):
queryset._add_hints(instance=instances[0])
queryset = queryset.using(queryset._db or self._db)
-
- query = {
- '%s__pk' % self.content_type_field_name: self.content_type.id,
- '%s__in' % self.object_id_field_name: {obj.pk for obj in instances}
- }
-
+ # Group instances by content types.
+ content_type_queries = (
+ models.Q(**{
+ '%s__pk' % self.content_type_field_name: content_type_id,
+ '%s__in' % self.object_id_field_name: {obj.pk for obj in objs}
+ })
+ for content_type_id, objs in itertools.groupby(
+ sorted(instances, key=lambda obj: self.get_content_type(obj).pk),
+ lambda obj: self.get_content_type(obj).pk,
+ )
+ )
+ query = functools.reduce(operator.or_, content_type_queries)
# We (possibly) need to convert object IDs to the type of the
# instances' PK in order to match up instances:
object_id_converter = instances[0]._meta.pk.to_python
return (
- queryset.filter(**query),
- lambda relobj: object_id_converter(getattr(relobj, self.object_id_field_name)),
- lambda obj: obj.pk,
+ queryset.filter(query),
+ lambda relobj: (
+ object_id_converter(getattr(relobj, self.object_id_field_name)),
+ relobj.content_type_id
+ ),
+ lambda obj: (obj.pk, self.get_content_type(obj).pk),
False,
self.prefetch_cache_name,
False,