diff --git a/AUTHORS b/AUTHORS
|
a
|
b
|
|
| 535 | 535 | ye7cakf02@sneakemail.com |
| 536 | 536 | ymasuda@ethercube.com |
| 537 | 537 | Jesse Young <adunar@gmail.com> |
| 538 | 538 | Mykola Zamkovoi <nickzam@gmail.com> |
| 539 | 539 | zegor |
| 540 | 540 | Gasper Zejn <zejn@kiberpipa.org> |
| 541 | 541 | Jarek Zgoda <jarek.zgoda@gmail.com> |
| 542 | 542 | Cheng Zhang |
| | 543 | Jeffrey Gelens <jeffrey@gelens.org> |
| 543 | 544 | |
| 544 | 545 | A big THANK YOU goes to: |
| 545 | 546 | |
| 546 | 547 | Rob Curley and Ralph Gage for letting us open-source Django. |
| 547 | 548 | |
| 548 | 549 | Frank Wiles for making excellent arguments for open-sourcing, and for |
| 549 | 550 | his sage sysadmin advice. |
| 550 | 551 | |
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
|
a
|
b
|
|
| 336 | 336 | |
| 337 | 337 | # Features that need to be confirmed at runtime |
| 338 | 338 | # Cache whether the confirmation has been performed. |
| 339 | 339 | _confirmed = False |
| 340 | 340 | supports_transactions = None |
| 341 | 341 | supports_stddev = None |
| 342 | 342 | can_introspect_foreign_keys = None |
| 343 | 343 | |
| | 344 | # Support for the DISTINCT ON clause |
| | 345 | can_distinct_on_fields = False |
| | 346 | |
| 344 | 347 | def __init__(self, connection): |
| 345 | 348 | self.connection = connection |
| 346 | 349 | |
| 347 | 350 | def confirm(self): |
| 348 | 351 | "Perform manual checks of any database features that might vary between installs" |
| 349 | 352 | self._confirmed = True |
| 350 | 353 | self.supports_transactions = self._supports_transactions() |
| 351 | 354 | self.supports_stddev = self._supports_stddev() |
| … |
… |
|
| 489 | 492 | def fulltext_search_sql(self, field_name): |
| 490 | 493 | """ |
| 491 | 494 | Returns the SQL WHERE clause to use in order to perform a full-text |
| 492 | 495 | search of the given field_name. Note that the resulting string should |
| 493 | 496 | contain a '%s' placeholder for the value being searched against. |
| 494 | 497 | """ |
| 495 | 498 | raise NotImplementedError('Full-text search is not implemented for this database backend') |
| 496 | 499 | |
| | 500 | def distinct(self, db_table, fields): |
| | 501 | """ |
| | 502 | Returns an SQL DISTINCT clause which removes duplicate rows from the |
| | 503 | result set. If any fields are given, only the given fields are being |
| | 504 | checked for duplicates. |
| | 505 | """ |
| | 506 | if fields: |
| | 507 | raise NotImplementedError('DISTINCT ON fields is not supported by this database backend') |
| | 508 | else: |
| | 509 | return 'DISTINCT' |
| | 510 | |
| 497 | 511 | def last_executed_query(self, cursor, sql, params): |
| 498 | 512 | """ |
| 499 | 513 | Returns a string of the query last executed by the given cursor, with |
| 500 | 514 | placeholders replaced with actual values. |
| 501 | 515 | |
| 502 | 516 | `sql` is the raw query containing placeholders, and `params` is the |
| 503 | 517 | sequence of parameters. These are used by default, but this method |
| 504 | 518 | exists for database backends to provide a better implementation |
diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py
|
a
|
b
|
|
| 66 | 66 | class DatabaseFeatures(BaseDatabaseFeatures): |
| 67 | 67 | needs_datetime_string_cast = False |
| 68 | 68 | can_return_id_from_insert = True |
| 69 | 69 | requires_rollback_on_dirty_transaction = True |
| 70 | 70 | has_real_datatype = True |
| 71 | 71 | can_defer_constraint_checks = True |
| 72 | 72 | has_select_for_update = True |
| 73 | 73 | has_select_for_update_nowait = True |
| | 74 | can_distinct_on_fields = True |
| 74 | 75 | |
| 75 | 76 | |
| 76 | 77 | class DatabaseWrapper(BaseDatabaseWrapper): |
| 77 | 78 | vendor = 'postgresql' |
| 78 | 79 | operators = { |
| 79 | 80 | 'exact': '= %s', |
| 80 | 81 | 'iexact': '= UPPER(%s)', |
| 81 | 82 | 'contains': 'LIKE %s', |
diff --git a/django/db/backends/postgresql_psycopg2/operations.py b/django/db/backends/postgresql_psycopg2/operations.py
|
a
|
b
|
|
| 168 | 168 | macro in src/include/pg_config_manual.h . |
| 169 | 169 | |
| 170 | 170 | This implementation simply returns 63, but can easily be overridden by a |
| 171 | 171 | custom database backend that inherits most of its behavior from this one. |
| 172 | 172 | """ |
| 173 | 173 | |
| 174 | 174 | return 63 |
| 175 | 175 | |
| | 176 | def distinct(self, db_table, fields): |
| | 177 | if fields: |
| | 178 | table_name = self.quote_name(db_table) |
| | 179 | fields = [table_name + "." + self.quote_name(field) for field in fields] |
| | 180 | return 'DISTINCT ON (%s)' % ', '.join(fields) |
| | 181 | else: |
| | 182 | return 'DISTINCT' |
| | 183 | |
| 176 | 184 | def last_executed_query(self, cursor, sql, params): |
| 177 | 185 | # http://initd.org/psycopg/docs/cursor.html#cursor.query |
| 178 | 186 | # The query attribute is a Psycopg extension to the DB API 2.0. |
| 179 | 187 | return cursor.query |
| 180 | 188 | |
| 181 | 189 | def return_insert_id(self): |
| 182 | 190 | return "RETURNING %s", () |
diff --git a/django/db/models/query.py b/django/db/models/query.py
|
a
|
b
|
|
| 660 | 660 | """ |
| 661 | 661 | assert self.query.can_filter(), \ |
| 662 | 662 | "Cannot reorder a query once a slice has been taken." |
| 663 | 663 | obj = self._clone() |
| 664 | 664 | obj.query.clear_ordering() |
| 665 | 665 | obj.query.add_ordering(*field_names) |
| 666 | 666 | return obj |
| 667 | 667 | |
| 668 | | def distinct(self, true_or_false=True): |
| | 668 | def distinct(self, *field_names): |
| 669 | 669 | """ |
| 670 | 670 | Returns a new QuerySet instance that will select only distinct results. |
| 671 | 671 | """ |
| 672 | 672 | obj = self._clone() |
| 673 | | obj.query.distinct = true_or_false |
| | 673 | obj.query.add_distinct_fields(field_names) |
| | 674 | obj.query.distinct = True |
| | 675 | |
| 674 | 676 | return obj |
| 675 | 677 | |
| 676 | 678 | def extra(self, select=None, where=None, params=None, tables=None, |
| 677 | 679 | order_by=None, select_params=None): |
| 678 | 680 | """ |
| 679 | 681 | Adds extra SQL fragments to the query. |
| 680 | 682 | """ |
| 681 | 683 | assert self.query.can_filter(), \ |
| … |
… |
|
| 1085 | 1087 | return self |
| 1086 | 1088 | |
| 1087 | 1089 | def order_by(self, *field_names): |
| 1088 | 1090 | """ |
| 1089 | 1091 | Always returns EmptyQuerySet. |
| 1090 | 1092 | """ |
| 1091 | 1093 | return self |
| 1092 | 1094 | |
| 1093 | | def distinct(self, true_or_false=True): |
| | 1095 | def distinct(self, fields=None): |
| 1094 | 1096 | """ |
| 1095 | 1097 | Always returns EmptyQuerySet. |
| 1096 | 1098 | """ |
| 1097 | 1099 | return self |
| 1098 | 1100 | |
| 1099 | 1101 | def extra(self, select=None, where=None, params=None, tables=None, |
| 1100 | 1102 | order_by=None, select_params=None): |
| 1101 | 1103 | """ |
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
|
a
|
b
|
|
| 69 | 69 | |
| 70 | 70 | where, w_params = self.query.where.as_sql(qn=qn, connection=self.connection) |
| 71 | 71 | having, h_params = self.query.having.as_sql(qn=qn, connection=self.connection) |
| 72 | 72 | params = [] |
| 73 | 73 | for val in self.query.extra_select.itervalues(): |
| 74 | 74 | params.extend(val[1]) |
| 75 | 75 | |
| 76 | 76 | result = ['SELECT'] |
| | 77 | |
| 77 | 78 | if self.query.distinct: |
| 78 | | result.append('DISTINCT') |
| | 79 | distinct_sql = self.connection.ops.distinct( |
| | 80 | self.query.model._meta.db_table, self.query.distinct_fields) |
| | 81 | result.append(distinct_sql) |
| | 82 | |
| 79 | 83 | result.append(', '.join(out_cols + self.query.ordering_aliases)) |
| 80 | 84 | |
| 81 | 85 | result.append('FROM') |
| 82 | 86 | result.extend(from_) |
| 83 | 87 | params.extend(f_params) |
| 84 | 88 | |
| 85 | 89 | if where: |
| 86 | 90 | result.append('WHERE %s' % where) |
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
|
a
|
b
|
|
| 120 | 120 | self.tables = [] # Aliases in the order they are created. |
| 121 | 121 | self.where = where() |
| 122 | 122 | self.where_class = where |
| 123 | 123 | self.group_by = None |
| 124 | 124 | self.having = where() |
| 125 | 125 | self.order_by = [] |
| 126 | 126 | self.low_mark, self.high_mark = 0, None # Used for offset/limit |
| 127 | 127 | self.distinct = False |
| | 128 | self.distinct_fields = None |
| 128 | 129 | self.select_for_update = False |
| 129 | 130 | self.select_for_update_nowait = False |
| 130 | 131 | self.select_related = False |
| 131 | 132 | self.related_select_cols = [] |
| 132 | 133 | |
| 133 | 134 | # SQL aggregate-related attributes |
| 134 | 135 | self.aggregates = SortedDict() # Maps alias -> SQL aggregate function |
| 135 | 136 | self.aggregate_select_mask = None |
| … |
… |
|
| 251 | 252 | if self.group_by is None: |
| 252 | 253 | obj.group_by = None |
| 253 | 254 | else: |
| 254 | 255 | obj.group_by = self.group_by[:] |
| 255 | 256 | obj.having = copy.deepcopy(self.having, memo=memo) |
| 256 | 257 | obj.order_by = self.order_by[:] |
| 257 | 258 | obj.low_mark, obj.high_mark = self.low_mark, self.high_mark |
| 258 | 259 | obj.distinct = self.distinct |
| | 260 | obj.distinct_fields = self.distinct_fields |
| 259 | 261 | obj.select_for_update = self.select_for_update |
| 260 | 262 | obj.select_for_update_nowait = self.select_for_update_nowait |
| 261 | 263 | obj.select_related = self.select_related |
| 262 | 264 | obj.related_select_cols = [] |
| 263 | 265 | obj.aggregates = copy.deepcopy(self.aggregates, memo=memo) |
| 264 | 266 | if self.aggregate_select_mask is None: |
| 265 | 267 | obj.aggregate_select_mask = None |
| 266 | 268 | else: |
| … |
… |
|
| 379 | 381 | in zip(query.aggregate_select.items(), result) |
| 380 | 382 | ]) |
| 381 | 383 | |
| 382 | 384 | def get_count(self, using): |
| 383 | 385 | """ |
| 384 | 386 | Performs a COUNT() query using the current filter constraints. |
| 385 | 387 | """ |
| 386 | 388 | obj = self.clone() |
| 387 | | if len(self.select) > 1 or self.aggregate_select: |
| | 389 | if len(self.select) > 1 or self.aggregate_select or (self.distinct and self.distinct_fields): |
| 388 | 390 | # If a select clause exists, then the query has already started to |
| 389 | 391 | # specify the columns that are to be returned. |
| 390 | 392 | # In this case, we need to use a subquery to evaluate the count. |
| 391 | 393 | from django.db.models.sql.subqueries import AggregateQuery |
| 392 | 394 | subquery = obj |
| 393 | 395 | subquery.clear_ordering(True) |
| 394 | 396 | subquery.clear_limits() |
| 395 | 397 | |
| … |
… |
|
| 1552 | 1554 | """ |
| 1553 | 1555 | Clears the list of fields to select (but not extra_select columns). |
| 1554 | 1556 | Some queryset types completely replace any existing list of select |
| 1555 | 1557 | columns. |
| 1556 | 1558 | """ |
| 1557 | 1559 | self.select = [] |
| 1558 | 1560 | self.select_fields = [] |
| 1559 | 1561 | |
| | 1562 | def add_distinct_fields(self, field_names): |
| | 1563 | self.distinct_fields = [] |
| | 1564 | options = self.get_meta() |
| | 1565 | |
| | 1566 | for name in field_names: |
| | 1567 | field, source, opts, join_list, last, _ = self.setup_joins( |
| | 1568 | name.split(LOOKUP_SEP), options, self.get_initial_alias(), False) |
| | 1569 | self.distinct_fields.append(field.column) |
| | 1570 | |
| 1560 | 1571 | def add_fields(self, field_names, allow_m2m=True): |
| 1561 | 1572 | """ |
| 1562 | 1573 | Adds the given (model) fields to the select set. The field names are |
| 1563 | 1574 | added in the order specified. |
| 1564 | 1575 | """ |
| 1565 | 1576 | alias = self.get_initial_alias() |
| 1566 | 1577 | opts = self.get_meta() |
| 1567 | 1578 | |
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
|
a
|
b
|
|
| 134 | 134 | introspection: |
| 135 | 135 | |
| 136 | 136 | .. attribute:: ordered |
| 137 | 137 | |
| 138 | 138 | ``True`` if the ``QuerySet`` is ordered -- i.e. has an order_by() |
| 139 | 139 | clause or a default ordering on the model. ``False`` otherwise. |
| 140 | 140 | |
| 141 | 141 | .. attribute:: db |
| 142 | | |
| | 142 | |
| 143 | 143 | The database that will be used if this query is executed now. |
| 144 | 144 | |
| 145 | 145 | .. note:: |
| 146 | 146 | |
| 147 | 147 | The ``query`` parameter to :class:`QuerySet` exists so that specialized |
| 148 | 148 | query subclasses such as |
| 149 | 149 | :class:`~django.contrib.gis.db.models.GeoQuerySet` can reconstruct |
| 150 | 150 | internal query state. The value of the parameter is an opaque |
| … |
… |
|
| 340 | 340 | ``order_by()``). If no such ordering is defined for a given |
| 341 | 341 | ``QuerySet``, calling ``reverse()`` on it has no real effect (the |
| 342 | 342 | ordering was undefined prior to calling ``reverse()``, and will remain |
| 343 | 343 | undefined afterward). |
| 344 | 344 | |
| 345 | 345 | distinct |
| 346 | 346 | ~~~~~~~~ |
| 347 | 347 | |
| 348 | | .. method:: distinct() |
| | 348 | .. method:: distinct(*fields) |
| 349 | 349 | |
| 350 | 350 | Returns a new ``QuerySet`` that uses ``SELECT DISTINCT`` in its SQL query. This |
| 351 | 351 | eliminates duplicate rows from the query results. |
| 352 | 352 | |
| 353 | 353 | By default, a ``QuerySet`` will not eliminate duplicate rows. In practice, this |
| 354 | 354 | is rarely a problem, because simple queries such as ``Blog.objects.all()`` |
| 355 | 355 | don't introduce the possibility of duplicate result rows. However, if your |
| 356 | 356 | query spans multiple tables, it's possible to get duplicate results when a |
| 357 | 357 | ``QuerySet`` is evaluated. That's when you'd use ``distinct()``. |
| 358 | 358 | |
| | 359 | .. versionadded:: 1.4 |
| | 360 | ``distinct()`` takes optional positional arguments ``*fields``, which specify |
| | 361 | field names to which the ``DISTINCT`` should be limited. This translates to |
| | 362 | a ``SELECT DISTINCT ON`` SQL query. Note that this ``DISTINCT ON`` query is |
| | 363 | only available in PostgreSQL. |
| | 364 | |
| | 365 | .. note:: |
| | 366 | When optional ``*fields`` are given, you will have to add an :meth:`order_by` |
| | 367 | call with the same field names as the leftmost arguments. |
| | 368 | |
| 359 | 369 | .. note:: |
| 360 | 370 | Any fields used in an :meth:`order_by` call are included in the SQL |
| 361 | 371 | ``SELECT`` columns. This can sometimes lead to unexpected results when |
| 362 | 372 | used in conjunction with ``distinct()``. If you order by fields from a |
| 363 | 373 | related model, those fields will be added to the selected columns and they |
| 364 | 374 | may make otherwise duplicate rows appear to be distinct. Since the extra |
| 365 | 375 | columns don't appear in the returned results (they are only there to |
| 366 | 376 | support ordering), it sometimes looks like non-distinct results are being |