| 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 |
|
|---|
| 25 |
def 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]) |
|---|