CookBookPreloadRelated: db.py

File db.py, 3.0 KB (added by Antti Kaihola, 18 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])
Back to Top