Code

CookBookPreloadRelated: db.py

File db.py, 3.0 KB (added by akaihola, 8 years ago)

first version

Line 
1#!/usr/bin/python
2# -*- encoding: utf-8 -*-
3
4##
5## ambidjangolib/db.py
6## Created on Wed Apr  5 23:26:18 2006
7## by Antti Kaihola <akaihola@ambitone.com>
8##
9## Copyright (C) 2006 Antti Kaihola
10## This program is free software; you can redistribute it and/or modify
11## it under the terms of the GNU General Public License as published by
12## the Free Software Foundation; either version 2 of the License, or
13## (at your option) any later version.
14##
15## This program is distributed in the hope that it will be useful,
16## but WITHOUT ANY WARRANTY; without even the implied warranty of
17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18## GNU General Public License for more details.
19##
20## You should have received a copy of the GNU General Public License
21## along with this program; if not, write to the Free Software
22## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23##
24
25def preload_related(objects, model, *related):
26    """
27    Given a queryset of objects, retrieves related objects and stores
28    them as lists into attributes of the original objects.
29
30    See http://code.djangoproject.com/wiki/CookBookPreloadRelated for
31    more information.
32
33    Example:
34    >>> users = User.objects.filter(username__startswith='a')
35    >>> preload_related(users,
36    ...                 User,
37    ...                 (UserProperty.objects, Property.objects, 'properties'),
38    ...                 (UserAlias.objects   , Alias.objects   , 'aliases'   ))
39    >>> users[0].properties
40    [<a list containing Property objects>]
41    >>> users[0].aliases
42    [<a list containing Alias objects>]
43    """
44   
45    # store the list of object IDs locally for performance
46    object_ids = [obj._get_pk_val() for obj in objects]
47   
48    cached_objects = {}
49   
50    for (m2m_set, rel_set, attr) in related:
51       
52        # name of ForeignKey field referring to main objects
53        leftfield  = [f.name for f in m2m_set.model._meta.fields
54                      if f.rel and f.rel.to._meta is model._meta][0]
55
56        # name of ForeignKey field referring to related objects
57        rightfield = [f.name for f in m2m_set.model._meta.fields
58                      if f.rel and f.rel.to._meta is rel_set.model._meta][0]
59
60        # query all m2m rows which refer to one of the main objects
61        # already in memory
62        criteria = {'%s__in' % leftfield: object_ids}
63        cached_objects[attr] = {
64            'field'  : rightfield,
65            'objects': m2m_set.filter(**criteria).select_related(True)}
66       
67    for obj in objects:
68        # store retrieved related objects into corresponding main
69        # objects
70        for attr, cachedict in cached_objects.iteritems():
71            rightfield = cachedict['field']
72            event_objects = [getattr(cached_obj, rightfield)
73                             for cached_obj in cached_objects[attr]['objects']
74                             if getattr(cached_obj, leftfield) == obj]
75            setattr(obj, attr, event_objects)
76            setattr(obj, attr+'_ids', [eo._get_pk_val() for eo in event_objects])