Commit 28756577 authored by Ramiro Morales's avatar Ramiro Morales
Browse files

Added support for modifying the effect of ``DISTINCT`` clauses so they

only consider some fields (PostgreSQL only).

For this, the ``distinct()`` QuerySet method now accepts an optional
list of model fields names and generates ``DISTINCT ON`` clauses on
these cases. Thanks Jeffrey Gelens and Anssi Kääriäinen for their work.

Fixes #6422.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17244 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 03eb2907
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -203,6 +203,7 @@ answer newbie questions, and generally made Django that much better:
    Marc Garcia <marc.garcia@accopensys.com>
    Andy Gayton <andy-django@thecablelounge.com>
    geber@datacollect.com
    Jeffrey Gelens <jeffrey@gelens.org>
    Baishampayan Ghose
    Joshua Ginsberg <jag@flowtheory.net>
    Dimitris Glezos <dimitris@glezos.com>
@@ -269,6 +270,7 @@ answer newbie questions, and generally made Django that much better:
    jpellerin@gmail.com
    junzhang.jn@gmail.com
    Xia Kai <http://blog.xiaket.org/>
    Anssi Kääriäinen
    Antti Kaihola <http://djangopeople.net/akaihola/>
    Peter van Kampen
    Bahadır Kandemir <bahadir@pardus.org.tr>
+14 −0
Original line number Diff line number Diff line
@@ -406,6 +406,9 @@ class BaseDatabaseFeatures(object):
    supports_stddev = None
    can_introspect_foreign_keys = None

    # Support for the DISTINCT ON clause
    can_distinct_on_fields = False

    def __init__(self, connection):
        self.connection = connection

@@ -559,6 +562,17 @@ class BaseDatabaseOperations(object):
        """
        raise NotImplementedError('Full-text search is not implemented for this database backend')

    def distinct_sql(self, fields):
        """
        Returns an SQL DISTINCT clause which removes duplicate rows from the
        result set. If any fields are given, only the given fields are being
        checked for duplicates.
        """
        if fields:
            raise NotImplementedError('DISTINCT ON fields is not supported by this database backend')
        else:
            return 'DISTINCT'

    def last_executed_query(self, cursor, sql, params):
        """
        Returns a string of the query last executed by the given cursor, with
+1 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
    has_select_for_update_nowait = True
    has_bulk_insert = True
    supports_tablespaces = True
    can_distinct_on_fields = True

class DatabaseWrapper(BaseDatabaseWrapper):
    vendor = 'postgresql'
+6 −0
Original line number Diff line number Diff line
@@ -179,6 +179,12 @@ class DatabaseOperations(BaseDatabaseOperations):

        return 63

    def distinct_sql(self, fields):
        if fields:
            return 'DISTINCT ON (%s)' % ', '.join(fields)
        else:
            return 'DISTINCT'

    def last_executed_query(self, cursor, sql, params):
        # http://initd.org/psycopg/docs/cursor.html#cursor.query
        # The query attribute is a Psycopg extension to the DB API 2.0.
+7 −3
Original line number Diff line number Diff line
@@ -323,6 +323,8 @@ class QuerySet(object):
        If args is present the expression is passed as a kwarg using
        the Aggregate object's default alias.
        """
        if self.query.distinct_fields:
            raise NotImplementedError("aggregate() + distinct(fields) not implemented.")
        for arg in args:
            kwargs[arg.default_alias] = arg

@@ -751,12 +753,14 @@ class QuerySet(object):
        obj.query.add_ordering(*field_names)
        return obj

    def distinct(self, true_or_false=True):
    def distinct(self, *field_names):
        """
        Returns a new QuerySet instance that will select only distinct results.
        """
        assert self.query.can_filter(), \
                "Cannot create distinct fields once a slice has been taken."
        obj = self._clone()
        obj.query.distinct = true_or_false
        obj.query.add_distinct_fields(*field_names)
        return obj

    def extra(self, select=None, where=None, params=None, tables=None,
@@ -1179,7 +1183,7 @@ class EmptyQuerySet(QuerySet):
        """
        return self

    def distinct(self, true_or_false=True):
    def distinct(self, fields=None):
        """
        Always returns EmptyQuerySet.
        """
Loading