Ticket #6821: aggregate.diff

File aggregate.diff, 4.2 KB (added by Nicolas Lara <nicolaslara@…>, 7 years ago)

aggregate modifier 0.1

  • django/db/models/sql/query.py

     
    5555        self.start_meta = None
    5656
    5757        # SQL-related attributes
     58        self.aggregates = []
    5859        self.select = []
    5960        self.tables = []    # Aliases in the order they are created.
    6061        self.where = where()
     
    139140        obj.standard_ordering = self.standard_ordering
    140141        obj.start_meta = self.start_meta
    141142        obj.select = self.select[:]
     143        obj.aggregates = self.aggregates[:]
    142144        obj.tables = self.tables[:]
    143145        obj.where = deepcopy(self.where)
    144146        obj.where_class = self.where_class
     
    171173                    row = self.resolve_columns(row, fields)
    172174                yield row
    173175
     176    def get_aggregation(self):
     177        for field in self.select:
     178            self.group_by.append(field)
     179        self.select.extend(self.aggregates)
     180        self.aggregates = []
     181        #print self.as_sql()
     182        #print self.select
     183
     184        get_name = lambda x : isinstance(x, tuple) and x[1] or x.aliased_name
     185
     186        if self.group_by:
     187            data = self.execute_sql(MULTI)
     188            result = []
     189            for rs in data.next():
     190                result.append(dict(zip([get_name(i) for i in self.select], rs)))
     191            return result
     192        else:
     193            data = self.execute_sql(SINGLE)
     194            return dict(zip([get_name(i) for i in self.select], data))
     195           
    174196    def get_count(self):
    175197        """
    176198        Performs a COUNT() query using the current filter constraints.
     
    806828            self.fill_related_selections(f.rel.to._meta, alias, cur_depth + 1,
    807829                    used, next, restricted)
    808830
     831    def add_aggregate(self, aggregate_expr, aliased_name, model):
     832        """
     833        Adds a single aggregate expression to the Query
     834        """
     835        #TODO: Aliases, Joins
     836
     837        field_list = aggregate_expr.split(LOOKUP_SEP)
     838        aggregate_func = field_list.pop()
     839       
     840        opts = model._meta
     841
     842        field_name = field_list[0]
     843
     844        #if len(field_list) > 1:
     845        #    field, target, opts, join_list, last = self.setup_joins(
     846        #        field_list, opts, self.get_initial_alias(), False)
     847           
     848        #Review Aliases
     849        class AggregateNode:
     850            def __init__(self, field_name, aggregate_func, aliased_name):
     851                self.field_name = field_name
     852                self.aggregate_func = aggregate_func
     853                self.aliased_name = aliased_name
     854                self.alias = '' #get table alias
     855               
     856            def as_sql(self, quote_func=None):
     857                return '%s(%s)' % (self.aggregate_func.upper(),
     858                                   self.field_name)
     859
     860        self.aggregates.append(AggregateNode(field_name, aggregate_func, aliased_name))
     861       
    809862    def add_filter(self, filter_expr, connector=AND, negate=False, trim=False,
    810863            merge_negated=False):
    811864        """
  • django/db/models/query.py

     
    154154                setattr(obj, k, row[index_end + i])
    155155            yield obj
    156156
     157    def aggregate(self, *args, **kwargs):
     158        """
     159        Returns the aggregation over the current model as values (or so it should).
     160        """
     161        if args:
     162            TypeError('Unexpected positional arguments')
     163           
     164        for (aggregate_expr, alias) in kwargs.items():
     165            self.query.add_aggregate(aggregate_expr, alias, self.model)
     166        return self.query.get_aggregation()
     167
    157168    def count(self):
    158169        """
    159170        Performs a SELECT COUNT() and returns the number of records as an
     
    328339        Returns a new QuerySet that is a copy of the current one. This allows a
    329340        QuerySet to proxy for a model manager in some cases.
    330341        """
    331         return self._clone()
     342        return self._clone()       
    332343
    333344    def filter(self, *args, **kwargs):
    334345        """
Back to Top