├── demo
├── __init__.py
├── demo_models
│ ├── __init__.py
│ ├── views.py
│ ├── admin.py
│ ├── models.py
│ └── tests.py
├── manage.py
├── urls.py
└── settings.py
├── MANIFEST.in
├── .gitignore
├── setup.py
├── queryset_transform
└── __init__.py
├── LICENSE
└── README.txt
/demo/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/demo/demo_models/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENSE
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ve
2 | demo/data.db
3 |
4 |
--------------------------------------------------------------------------------
/demo/demo_models/views.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 |
--------------------------------------------------------------------------------
/demo/demo_models/admin.py:
--------------------------------------------------------------------------------
1 | from models import Tag, Item
2 | from django.contrib import admin
3 |
4 | admin.site.register(Tag)
5 | admin.site.register(Item)
6 |
--------------------------------------------------------------------------------
/demo/demo_models/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from queryset_transform import TransformManager
3 |
4 | class Tag(models.Model):
5 | name = models.CharField(max_length = 255)
6 |
7 | def __unicode__(self):
8 | return self.name
9 |
10 | class Item(models.Model):
11 | name = models.CharField(max_length = 255)
12 | tags = models.ManyToManyField(Tag)
13 |
14 | objects = TransformManager()
15 |
16 | def __unicode__(self):
17 | return self.name
18 |
--------------------------------------------------------------------------------
/demo/demo_models/tests.py:
--------------------------------------------------------------------------------
1 | """
2 | This file demonstrates two different styles of tests (one doctest and one
3 | unittest). These will both pass when you run "manage.py test".
4 |
5 | Replace these with more appropriate tests for your application.
6 | """
7 |
8 | from django.test import TestCase
9 |
10 | class SimpleTest(TestCase):
11 | def test_basic_addition(self):
12 | """
13 | Tests that 1 + 1 always equals 2.
14 | """
15 | self.failUnlessEqual(1 + 1, 2)
16 |
17 | __test__ = {"doctest": """
18 | Another way to test that 1 + 1 is equal to 2.
19 |
20 | >>> 1 + 1 == 2
21 | True
22 | """}
23 |
24 |
--------------------------------------------------------------------------------
/demo/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import sys
3 | sys.path.append('../')
4 |
5 | from django.core.management import execute_manager
6 | try:
7 | import settings # Assumed to be in the same directory.
8 | except ImportError:
9 | import sys
10 | sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
11 | sys.exit(1)
12 |
13 | if __name__ == "__main__":
14 | execute_manager(settings)
15 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from distutils.core import setup
2 | import os
3 |
4 | setup(
5 | name = 'django-queryset-transform',
6 | packages = ['queryset_transform'],
7 | version='0.0.2',
8 | description='Experimental .transform(fn) method for Django QuerySets, for '
9 | 'clever lazily evaluated optimisations.',
10 | long_description=open('README.txt').read(),
11 | author='Simon Willison',
12 | author_email='simon@simonwillison.net',
13 | url='http://github.com/simonw/django-queryset-transform',
14 | license='BSD',
15 | classifiers=[
16 | 'Development Status :: 4 - Beta',
17 | 'Environment :: Web Environment',
18 | 'Framework :: Django',
19 | 'Intended Audience :: Developers',
20 | 'License :: OSI Approved :: BSD License',
21 | 'Operating System :: OS Independent',
22 | 'Programming Language :: Python',
23 | 'Topic :: Software Development :: Libraries :: Python Modules',
24 | ],
25 | )
26 |
--------------------------------------------------------------------------------
/queryset_transform/__init__.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | class TransformQuerySet(models.query.QuerySet):
4 | def __init__(self, *args, **kwargs):
5 | super(TransformQuerySet, self).__init__(*args, **kwargs)
6 | self._transform_fns = []
7 |
8 | def _clone(self, klass=None, setup=False, **kw):
9 | c = super(TransformQuerySet, self)._clone(klass, setup, **kw)
10 | c._transform_fns = self._transform_fns[:]
11 | return c
12 |
13 | def transform(self, fn):
14 | c = self._clone()
15 | c._transform_fns.append(fn)
16 | return c
17 |
18 | def iterator(self):
19 | result_iter = super(TransformQuerySet, self).iterator()
20 | if self._transform_fns:
21 | results = list(result_iter)
22 | for fn in self._transform_fns:
23 | fn(results)
24 | return iter(results)
25 | return result_iter
26 |
27 | class TransformManager(models.Manager):
28 |
29 | def get_query_set(self):
30 | return TransformQuerySet(self.model)
31 |
--------------------------------------------------------------------------------
/demo/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls.defaults import *
2 | from django.contrib import admin
3 | from django.http import HttpResponse
4 | from django.db import connection
5 |
6 | from demo_models.models import Item, Tag
7 |
8 | from pprint import pformat
9 |
10 | admin.autodiscover()
11 |
12 | def example(request):
13 | def lookup_tags(item_qs):
14 | item_pks = [item.pk for item in item_qs]
15 | m2mfield = Item._meta.get_field_by_name('tags')[0]
16 | tags_for_item = Tag.objects.filter(
17 | item__in = item_pks
18 | ).extra(select = {
19 | 'item_id': '%s.%s' % (
20 | m2mfield.m2m_db_table(), m2mfield.m2m_column_name()
21 | )
22 | })
23 | tag_dict = {}
24 | for tag in tags_for_item:
25 | tag_dict.setdefault(tag.item_id, []).append(tag)
26 | for item in item_qs:
27 | item.fetched_tags = tag_dict.get(item.pk, [])
28 |
29 | qs = Item.objects.all().transform(lookup_tags)
30 |
31 | s = []
32 |
33 | for item in qs:
34 | s.append('%s: %s' % (item, [t.name for t in item.fetched_tags]))
35 |
36 | return HttpResponse(
37 | '
'.join(s) + '
%s