Ticket #6422: query.py.2.patch

File query.py.2.patch, 4.5 KB (added by Manfred Wassmann <manolo@…>, 12 years ago)

New patch fixes count method and resolves quoting issues

  • query.py

    old new  
    186186        extra_select = self._select.items()
    187187
    188188        cursor = connection.cursor()
    189         cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
    190 
     189        select, sql, params = self._get_sql_clause()
     190        if self._distinct == False:
     191            distinct = ""
     192        elif self._distinct == True:
     193            distinct = "DISTINCT "
     194        else:
     195            distinct = "DISTINCT ON (%s) " % (','.join(self._distinct))
     196        cursor.execute("SELECT " + distinct + ",".join(select) + sql, params)
    191197        fill_cache = self._select_related
    192198        fields = self.model._meta.fields
    193199        index_end = len(fields)
     
    236242
    237243        cursor = connection.cursor()
    238244        if self._distinct:
    239             id_col = "%s.%s" % (connection.ops.quote_name(self.model._meta.db_table),
     245            table, column = None, None
     246            if self._distinct == True:
     247                # Simple DISTINCT  query
     248                id_col = "%s.%s" % (
     249                    connection.ops.quote_name(self.model._meta.db_table),
    240250                    connection.ops.quote_name(self.model._meta.pk.column))
    241             cursor.execute("SELECT COUNT(DISTINCT(%s))" % id_col + sql, params)
    242         else:
    243             cursor.execute("SELECT COUNT(*)" + sql, params)
     251            elif len(self._distinct) == 1:
     252                # DISTINCT ON query with single field
     253                id_col = self._distinct[0]
     254            else:
     255                # DISTINCT ON with multiple fields: emulate SELECT COUNT
     256                id_col = "%s.%s" % (
     257                    connection.ops.quote_name(self.model._meta.db_table),
     258                    connection.ops.quote_name(self.model._meta.pk.column))
     259                cursor.execute("SELECT DISTINCT ON (%s) %s " % (
     260                        ','.join(self._distinct), id_col) + sql, params)
     261                # Don't have to correct the result for OFFSET and LIMIT as
     262                # we performed an ordinary query.
     263                return(len(cursor.fetchall()))
     264
     265            cursor.execute("SELECT COUNT(DISTINCT(%s))" % id_col + sql,
     266                           params)
     267
    244268        count = cursor.fetchone()[0]
    245269
    246270        # Apply any offset and limit constraints manually, since using LIMIT or
     
    421445                "Cannot reorder a query once a slice has been taken."
    422446        return self._clone(_order_by=field_names)
    423447
    424     def distinct(self, true_or_false=True):
     448    def distinct(self, true_or_false=True, on_fields=None):
    425449        "Returns a new QuerySet instance with '_distinct' modified."
     450        if on_fields:
     451            if type(on_fields) == type(''):
     452                on_fields = (on_fields,)
     453            # Quote the field names
     454            on_fields = [
     455                connection.ops.quote_name(len(p) == 1
     456                                          and self.model._meta.db_table
     457                                          or p[0])
     458                + '.' + connection.ops.quote_name(p[-1])
     459                for p in [f.split('.',1) for f in on_fields]]
     460            return self._clone(_distinct=on_fields)
    426461        return self._clone(_distinct=true_or_false)
    427462
    428463    def extra(self, select=None, where=None, params=None, tables=None):
     
    462497        assert self._limit is None and self._offset is None \
    463498            and other._limit is None and other._offset is None, \
    464499            "Cannot combine queries once a slice has been taken."
     500        # CHECKME: for DISTINCT ON queries this will always return false
     501        # unless both field sets are identical. I don't know if this is
     502        # correct, if so the error message may have to be adapted.
    465503        assert self._distinct == other._distinct, \
    466504            "Cannot combine a unique query with a non-unique query"
    467505        #  use 'other's order by
     
    617655            field_names.extend([f[0] for f in extra_select])
    618656
    619657        cursor = connection.cursor()
    620         cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
     658        if self._distinct == False:
     659            distinct = ""
     660        elif self._distinct == True:
     661            distinct = "DISTINCT "
     662        else:
     663            distinct = "DISTINCT ON (%s) " % (','.join(self._distinct))
     664        cursor.execute("SELECT " + distinct + ",".join(select) + sql, params)
    621665
    622666        has_resolve_columns = hasattr(self, 'resolve_columns')
    623667        while 1:
Back to Top