@@ -237,13 +237,18 @@ def get_query_set(self, **db_hints):
237237 return self .related .model ._base_manager .using (db )
238238
239239 def get_prefetch_query_set (self , instances ):
240- vals = set (instance ._get_pk_val () for instance in instances )
241- params = {'%s__pk__in' % self .related .field .name : vals }
242- return (self .get_query_set (instance = instances [0 ]).filter (** params ),
243- attrgetter (self .related .field .attname ),
244- lambda obj : obj ._get_pk_val (),
245- True ,
246- self .cache_name )
240+ rel_obj_attr = attrgetter (self .related .field .attname )
241+ instance_attr = lambda obj : obj ._get_pk_val ()
242+ instances_dict = dict ((instance_attr (inst ), inst ) for inst in instances )
243+ params = {'%s__pk__in' % self .related .field .name : instances_dict .keys ()}
244+ qs = self .get_query_set (instance = instances [0 ]).filter (** params )
245+ # Since we're going to assign directly in the cache,
246+ # we must manage the reverse relation cache manually.
247+ rel_obj_cache_name = self .related .field .get_cache_name ()
248+ for rel_obj in qs :
249+ instance = instances_dict [rel_obj_attr (rel_obj )]
250+ setattr (rel_obj , rel_obj_cache_name , instance )
251+ return qs , rel_obj_attr , instance_attr , True , self .cache_name
247252
248253 def __get__ (self , instance , instance_type = None ):
249254 if instance is None :
@@ -324,17 +329,23 @@ def get_query_set(self, **db_hints):
324329 return QuerySet (self .field .rel .to ).using (db )
325330
326331 def get_prefetch_query_set (self , instances ):
327- vals = set (getattr (instance , self .field .attname ) for instance in instances )
332+ rel_obj_attr = attrgetter (self .field .rel .field_name )
333+ instance_attr = attrgetter (self .field .attname )
334+ instances_dict = dict ((instance_attr (inst ), inst ) for inst in instances )
328335 other_field = self .field .rel .get_related_field ()
329336 if other_field .rel :
330- params = {'%s__pk__in' % self .field .rel .field_name : vals }
337+ params = {'%s__pk__in' % self .field .rel .field_name : instances_dict . keys () }
331338 else :
332- params = {'%s__in' % self .field .rel .field_name : vals }
333- return (self .get_query_set (instance = instances [0 ]).filter (** params ),
334- attrgetter (self .field .rel .field_name ),
335- attrgetter (self .field .attname ),
336- True ,
337- self .cache_name )
339+ params = {'%s__in' % self .field .rel .field_name : instances_dict .keys ()}
340+ qs = self .get_query_set (instance = instances [0 ]).filter (** params )
341+ # Since we're going to assign directly in the cache,
342+ # we must manage the reverse relation cache manually.
343+ if not self .field .rel .multiple :
344+ rel_obj_cache_name = self .field .related .get_cache_name ()
345+ for rel_obj in qs :
346+ instance = instances_dict [rel_obj_attr (rel_obj )]
347+ setattr (rel_obj , rel_obj_cache_name , instance )
348+ return qs , rel_obj_attr , instance_attr , True , self .cache_name
338349
339350 def __get__ (self , instance , instance_type = None ):
340351 if instance is None :
@@ -467,18 +478,24 @@ def get_query_set(self):
467478 return self .instance ._prefetched_objects_cache [rel_field .related_query_name ()]
468479 except (AttributeError , KeyError ):
469480 db = self ._db or router .db_for_read (self .model , instance = self .instance )
470- return super (RelatedManager , self ).get_query_set ().using (db ).filter (** self .core_filters )
481+ qs = super (RelatedManager , self ).get_query_set ().using (db ).filter (** self .core_filters )
482+ qs ._known_related_object = (rel_field .name , self .instance )
483+ return qs
471484
472485 def get_prefetch_query_set (self , instances ):
486+ rel_obj_attr = attrgetter (rel_field .get_attname ())
487+ instance_attr = attrgetter (attname )
488+ instances_dict = dict ((instance_attr (inst ), inst ) for inst in instances )
473489 db = self ._db or router .db_for_read (self .model , instance = instances [0 ])
474- query = {'%s__%s__in' % (rel_field .name , attname ):
475- set (getattr (obj , attname ) for obj in instances )}
490+ query = {'%s__%s__in' % (rel_field .name , attname ): instances_dict .keys ()}
476491 qs = super (RelatedManager , self ).get_query_set ().using (db ).filter (** query )
477- return (qs ,
478- attrgetter (rel_field .get_attname ()),
479- attrgetter (attname ),
480- False ,
481- rel_field .related_query_name ())
492+ # Since we just bypassed this class' get_query_set(), we must manage
493+ # the reverse relation manually.
494+ for rel_obj in qs :
495+ instance = instances_dict [rel_obj_attr (rel_obj )]
496+ setattr (rel_obj , rel_field .name , instance )
497+ cache_name = rel_field .related_query_name ()
498+ return qs , rel_obj_attr , instance_attr , False , cache_name
482499
483500 def add (self , * objs ):
484501 for obj in objs :
0 commit comments