def prefetch_related_objects(result_cache, related_lookups):
    """
    Helper function for prefetch_related functionality

    Populates prefetched objects caches for a list of results
    from a QuerySet
    """
    if len(result_cache) == 0:
        return # nothing to do

    model = result_cache[0].__class__

    # We need to be able to dynamically add to the list of prefetch_related
    # lookups that we look up (see below).  So we need some book keeping to
    # ensure we don't do duplicate work.
    done_lookups = set() # list of lookups like foo__bar__baz
    done_queries = {}    # dictionary of things like 'foo__bar': [results]

    auto_lookups = [] # we add to this as we go through.
    followed_descriptors = set() # recursion protection

    all_lookups = itertools.chain(related_lookups, auto_lookups)
    for lookup in all_lookups:
        if lookup in done_lookups:
            # We've done exactly this already, skip the whole thing
            continue
        done_lookups.add(lookup)

        # Top level, the list of objects to decorate is the result cache
        # from the primary QuerySet. It won't be for deeper levels.
        obj_list = result_cache

        attrs = lookup.split(LOOKUP_SEP)
        for level, attr in enumerate(attrs):
            # Prepare main instances
            if len(obj_list) == 0:
                break

            good_objects = True
            for obj in obj_list:
                if not hasattr(obj, '_prefetched_objects_cache'):
                    try:
                        obj._prefetched_objects_cache = {}
                    except __HOLE__:
                        # Must be in a QuerySet subclass that is not returning
                        # Model instances, either in Django or 3rd
                        # party. prefetch_related() doesn't make sense, so quit
                        # now.
                        good_objects = False
                        break
                else:
                    # We already did this list
                    break
            if not good_objects:
                break

            # Descend down tree

            # We assume that objects retrieved are homogenous (which is the premise
            # of prefetch_related), so what applies to first object applies to all.
            first_obj = obj_list[0]
            prefetcher, descriptor, attr_found, is_fetched = get_prefetcher(first_obj, attr)

            if not attr_found:
                raise AttributeError("Cannot find '%s' on %s object, '%s' is an invalid "
                                     "parameter to prefetch_related()" %
                                     (attr, first_obj.__class__.__name__, lookup))

            if level == len(attrs) - 1 and prefetcher is None:
                # Last one, this *must* resolve to something that supports
                # prefetching, otherwise there is no point adding it and the
                # developer asking for it has made a mistake.
                raise ValueError("'%s' does not resolve to a item that supports "
                                 "prefetching - this is an invalid parameter to "
                                 "prefetch_related()." % lookup)

            if prefetcher is not None and not is_fetched:
                # Check we didn't do this already
                current_lookup = LOOKUP_SEP.join(attrs[0:level+1])
                if current_lookup in done_queries:
                    obj_list = done_queries[current_lookup]
                else:
                    obj_list, additional_prl = prefetch_one_level(obj_list, prefetcher, attr)
                    # We need to ensure we don't keep adding lookups from the
                    # same relationships to stop infinite recursion. So, if we
                    # are already on an automatically added lookup, don't add
                    # the new lookups from relationships we've seen already.
                    if not (lookup in auto_lookups and
                            descriptor in followed_descriptors):
                        for f in additional_prl:
                            new_prl = LOOKUP_SEP.join([current_lookup, f])
                            auto_lookups.append(new_prl)
                        done_queries[current_lookup] = obj_list
                    followed_descriptors.add(descriptor)
            else:
                # Either a singly related object that has already been fetched
                # (e.g. via select_related), or hopefully some other property
                # that doesn't support prefetching but needs to be traversed.

                # We replace the current list of parent objects with the list
                # of related objects, filtering out empty or missing values so
                # that we can continue with nullable or reverse relations.
                new_obj_list = []
                for obj in obj_list:
                    try:
                        new_obj = getattr(obj, attr)
                    except exceptions.ObjectDoesNotExist:
                        continue
                    if new_obj is None:
                        continue
                    new_obj_list.append(new_obj)
                obj_list = new_obj_list
dataset/ETHPy150Open AppScale/appscale/AppServer/lib/django-1.5/django/db/models/query.py/prefetch_related_objects