Author: floguy
Date: Sun Sep 21 19:54:40 2008
New Revision: 32
Modified:
trunk/things/__init__.py
trunk/things/fields.py
trunk/things/options.py
trunk/thingsproject/dev.db
trunk/thingsproject/twitter/admin.py
trunk/thingsproject/twitter/models.py
trunk/thingsproject/twitter/thing.py
trunk/thingsproject/urls.py
Log:
Refactored the aggregate support to be a bit more DRY (using multiple
inhericance O_o). Also added support for ordering based on sums either
from GenericForeignKeys or direct Foreign Keys.
Modified: trunk/things/__init__.py
==============================================================================
--- trunk/things/__init__.py (original)
+++ trunk/things/__init__.py Sun Sep 21 19:54:40 2008
@@ -1,6 +1,7 @@
from things.options import ModelThing, BaseThing
from things.sites import ThingSite, site
from things.fields import OrderField, OrderCountField,
OrderGenericCountField
+from things.fields import OrderSumField, OrderGenericSumField
def autodiscover():
"""
Modified: trunk/things/fields.py
==============================================================================
--- trunk/things/fields.py (original)
+++ trunk/things/fields.py Sun Sep 21 19:54:40 2008
@@ -7,6 +7,8 @@
__all__ = ('OrderField', )
+qn = connection.ops.quote_name
+
def create_setter(prop):
def inner(self, value):
setattr(self, prop, value)
@@ -15,8 +17,6 @@
class BaseField(object):
parent = None
field_name = None
- modifies_query_set = False
- is_aggregate = False
class OrderField(BaseField):
def __init__(self, verbose_name_asc=None, verbose_name_desc=None,
@@ -80,16 +80,23 @@
'url_prefix': self.parent.url_prefix,
})
-class OrderCountField(OrderField):
- modifies_query_set = True
- is_aggregate=True
+class AggregateBase(object):
+ def get_aggregate_name(self):
+ raise NotImplementedError
- def _get_aggregate_name(self):
- return '%s_count' % self.field_name
- aggregate_name = property(_get_aggregate_name)
+ def get_aggregate_sql(self):
+ raise NotImplementedError
+
+ def get_sql_args(self):
+ raise NotImplementedError
def modify_query_set(self, qs):
- qn = connection.ops.quote_name
+ sql = self.get_aggregate_sql()
+ args = self.get_sql_args()
+ return qs.extra(select={self.get_aggregate_name(): sql % args})
+
+class ForeignKeyAggregate(AggregateBase):
+ def get_sql_args(self):
try:
parent_field = self.parent.opts.get_field(self.field_name)
m2m = True
@@ -115,36 +122,89 @@
raise ValueError("Could not determine relationship on
related name %s" % self.field_name)
related_table = qn(related_table)
related_column_name = qn(related_column_name)
-
- SQL = """
+ return {
+ 'related_table': related_table,
+ 'related_column_name': related_column_name,
+ 'self_table': self_table,
+ }
+
+class GenericForeignKeyAggregate(AggregateBase):
+ def get_sql_args(self):
+ related_table = qn(self.generic_model._meta.db_table)
+ self_content_type = int(ContentType.objects.get_for_model(
+ self.parent.model).id)
+ self_table = qn(self.parent.model._meta.db_table)
+ return {
+ 'related_table': related_table,
+ 'self_content_type': self_content_type,
+ 'self_table': self_table,
+ }
+
+class OrderSumField(OrderField, ForeignKeyAggregate):
+ def __init__(self, sum_field, *args, **kwargs):
+ self.sum_field = sum_field
+ super(OrderSumField, self).__init__(*args, **kwargs)
+
+ def get_aggregate_sql(self):
+ return """
+ SELECT COALESCE(SUM(%(sum_field)s), 0)
+ FROM %(related_table)s
+ WHERE %(related_table)s.%(related_column_name)s
= %(self_table)s.id
+ """
+
+ def get_aggregate_name(self):
+ return '%s_sum' % self.field_name
+
+ def get_sql_args(self):
+ args = super(OrderSumField, self).get_sql_args().copy()
+ args.update({'sum_field': self.sum_field})
+ return args
+
+class OrderCountField(OrderField, ForeignKeyAggregate):
+ def get_aggregate_name(self):
+ return '%s_count' % self.field_name
+
+ def get_aggregate_sql(self):
+ return """
SELECT COUNT(*)
FROM %(related_table)s
WHERE %(related_table)s.%(related_column_name)s = %(self_table)s.id
- """ % locals()
- return qs.extra(select={self.aggregate_name: SQL})
-
-class OrderGenericCountField(OrderField):
- modifies_query_set = True
- is_aggregate = True
+ """
+class OrderGenericCountField(OrderField, GenericForeignKeyAggregate):
def __init__(self, generic_model, *args, **kwargs):
self.generic_model = generic_model
super(OrderGenericCountField, self).__init__(*args, **kwargs)
- def _get_aggregate_name(self):
+ def get_aggregate_name(self):
return '%s_count' % self.field_name
- aggregate_name = property(_get_aggregate_name)
- def modify_query_set(self, qs):
- qn = connection.ops.quote_name
- related_table = qn(self.generic_model._meta.db_table)
- self_content_type = int(ContentType.objects.get_for_model(
- self.parent.model).id)
- self_table = qn(self.parent.model._meta.db_table)
- SQL = u"""
+ def get_aggregate_sql(self):
+ return u"""
SELECT COUNT(*)
FROM %(related_table)s
WHERE %(related_table)s.content_type_id=%(self_content_type)i
AND %(related_table)s.object_id=%(self_table)s.id
- """ % locals()
- return qs.extra(select={self.aggregate_name: SQL})
\ No newline at end of file
+ """
+
+class OrderGenericSumField(OrderField, GenericForeignKeyAggregate):
+ def __init__(self, generic_model, sum_field, *args, **kwargs):
+ self.generic_model = generic_model
+ self.sum_field = sum_field
+ super(OrderGenericSumField, self).__init__(*args, **kwargs)
+
+ def get_aggregate_name(self):
+ return '%s_count' % self.field_name
+
+ def get_sql_args(self):
+ args = super(OrderGenericSumField, self).get_sql_args().copy()
+ args.update({'sum_field': self.sum_field})
+ return args
+
+ def get_aggregate_sql(self):
+ return u"""
+ SELECT COALESCE(SUM(%(sum_field)s), 0)
+ FROM %(related_table)s
+ WHERE %(related_table)s.content_type_id=%(self_content_type)i
+ AND %(related_table)s.object_id=%(self_table)s.id
+ """
\ No newline at end of file
Modified: trunk/things/options.py
==============================================================================
--- trunk/things/options.py (original)
+++ trunk/things/options.py Sun Sep 21 19:54:40 2008
@@ -7,7 +7,7 @@
from django.template.loader import select_template
from django.core.urlresolvers import reverse
from django.db.models import Q
-from things.fields import BaseField, OrderCountField
+from things.fields import BaseField, OrderCountField, AggregateBase
DETAIL_RE = re.compile('^(\d+)/$')
@@ -59,8 +59,8 @@
pre = ''
if descending == True:
pre = '-'
- if field.is_aggregate:
- items = items.order_by('%s%s' % (pre,
field.aggregate_name))
+ if isinstance(field, AggregateBase):
+ items = items.order_by('%s%s' % (pre,
field.get_aggregate_name()))
else:
items = items.order_by('%s%s' % (pre, field.field_name))
templates = ['%s/%s' % (self.template_dir, template_name,),
@@ -134,7 +134,7 @@
def get_query_set(self):
query_set = self.model._default_manager.all()
for field_name, field in self.fields.iteritems():
- if field.modifies_query_set:
+ if isinstance(field, AggregateBase):
query_set = field.modify_query_set(query_set)
return query_set
Modified: trunk/thingsproject/dev.db
==============================================================================
Binary files. No diff available.
Modified: trunk/thingsproject/twitter/admin.py
==============================================================================
--- trunk/thingsproject/twitter/admin.py (original)
+++ trunk/thingsproject/twitter/admin.py Sun Sep 21 19:54:40 2008
@@ -1,5 +1,7 @@
from django.contrib import admin
from models import Tweet
+from models import Vote
-admin.site.register(Tweet)
\ No newline at end of file
+admin.site.register(Tweet)
+admin.site.register(Vote)
\ No newline at end of file
Modified: trunk/thingsproject/twitter/models.py
==============================================================================
--- trunk/thingsproject/twitter/models.py (original)
+++ trunk/thingsproject/twitter/models.py Sun Sep 21 19:54:40 2008
@@ -11,3 +11,7 @@
class Admin:
pass
+
+class Vote(models.Model):
+ value = models.IntegerField()
+ tweet = models.ForeignKey(Tweet)
\ No newline at end of file
Modified: trunk/thingsproject/twitter/thing.py
==============================================================================
--- trunk/thingsproject/twitter/thing.py (original)
+++ trunk/thingsproject/twitter/thing.py Sun Sep 21 19:54:40 2008
@@ -5,6 +5,7 @@
date_posted = things.OrderField(verbose_name_asc='Newest',
verbose_name_desc='Oldest', url_asc='newest', url_desc='oldest',
field_url='date')
+ vote_set = things.OrderSumField('value')
message = things.OrderField()
search = ('message', 'date_posted')
Modified: trunk/thingsproject/urls.py
==============================================================================
--- trunk/thingsproject/urls.py (original)
+++ trunk/thingsproject/urls.py Sun Sep 21 19:54:40 2008
@@ -12,4 +12,4 @@
urlpatterns = patterns('',
(r'^admin/(.*)$', admin.site.root),
-) + tt.urls(url_prefix='tweets')
\ No newline at end of file
+) + tt.urls(url_prefix='tweets/')
\ No newline at end of file
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"pinax-updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/pinax-updates?hl=en
-~----------~----~----~----~------~----~------~--~---