Ticket #4997: query.py.diff

File query.py.diff, 4.2 KB (added by David Cramer <dcramer@…>, 8 years ago)
  • django/trunk/django/db/models/query.py

     
    8888        self.model = model
    8989        self._filters = Q()
    9090        self._order_by = None        # Ordering, e.g. ('date', '-name'). If None, use model's ordering.
     91        self._group_by = []        # Grouping, e.g. ('foreignkey').
    9192        self._select_related = False # Whether to fill cache for related objects.
    9293        self._max_related_depth = 0  # Maximum "depth" for select_related
    9394        self._distinct = False       # Whether the query should use SELECT DISTINCT.
     
    215216        If the queryset is already cached (i.e. self._result_cache is set) this
    216217        simply returns the length of the cached results set to avoid multiple
    217218        SELECT COUNT(*) calls.
     219
     220        If they were using GROUP_BY we have to change this to a COUNT(DISTINCT).
    218221        """
    219222        if self._result_cache is not None:
    220223            return len(self._result_cache)
     
    228231        counter._offset = None
    229232        counter._limit = None
    230233
     234        if counter._group_by:
     235            id_col = ", ".join(counter.groupby2columns(self.model._meta))
     236            counter._group_by = ()
     237            counter._distinct = True
     238        elif self._distinct:
     239            id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table),
     240                backend.quote_name(self.model._meta.pk.column))
     241
    231242        try:
    232243            select, sql, params = counter._get_sql_clause()
    233244        except EmptyResultSet:
     
    418429                "Cannot reorder a query once a slice has been taken."
    419430        return self._clone(_order_by=field_names)
    420431
     432    def group_by(self, *field_names):
     433        "Returns a new QuerySet instance with '_group_by' modified."
     434        return self._clone(_group_by=field_names)
     435
    421436    def distinct(self, true_or_false=True):
    422437        "Returns a new QuerySet instance with '_distinct' modified."
    423438        return self._clone(_distinct=true_or_false)
     
    443458        c.model = self.model
    444459        c._filters = self._filters
    445460        c._order_by = self._order_by
     461        c._group_by = self._group_by
    446462        c._select_related = self._select_related
    447463        c._max_related_depth = self._max_related_depth
    448464        c._distinct = self._distinct
     
    473489        if (self._order_by is not None and len(self._order_by) > 0) and \
    474490           (combined._order_by is None or len(combined._order_by) == 0):
    475491            combined._order_by = self._order_by
     492        if (self._group_by is not None and len(self._group_by) > 0) and \
     493           (combined._group_by is None or len(combined._group_by) == 0):
     494            combined._group_by = self._group_by
    476495        return combined
    477496
    478497    def _get_data(self):
     
    523542        if where:
    524543            sql.append(where and "WHERE " + " AND ".join(where))
    525544
     545        # GROUP BY clause
     546        group_by = self.groupby2columns(opts)
     547        if group_by:
     548            sql.append("GROUP BY " + ", ".join(group_by))
     549
    526550        # ORDER BY clause
    527551        order_by = []
    528552        if self._order_by is not None:
     
    561585
    562586        return select, " ".join(sql), params
    563587
     588    def groupby2columns(self, opts):
     589        group_by = []
     590        for col_name in self._group_by:
     591            if "." in col_name:
     592                table_prefix, col_name = col_name.split('.', 1)
     593                table_prefix = backend.quote_name(table_prefix) + '.'
     594            else:
     595                # Use the database table as a column prefix if it wasn't given,
     596                # and if the requested column isn't a custom SELECT.
     597                if "." not in col_name and col_name not in (self._select or ()):
     598                    table_prefix = backend.quote_name(opts.db_table) + '.'
     599                else:
     600                    table_prefix = ''
     601            group_by.append('%s%s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts))))
     602        return group_by
     603
    564604# Use the backend's QuerySet class if it defines one, otherwise use _QuerySet.
    565605if hasattr(backend, 'get_query_set_class'):
    566606    QuerySet = backend.get_query_set_class(_QuerySet)
Back to Top