diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 223e516d56..c3c8e55793 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -9,6 +9,7 @@ all about the internals of models in order to get the information it needs. from collections import OrderedDict import copy +import warnings from django.utils.encoding import force_text from django.utils.tree import Node @@ -1036,6 +1037,9 @@ class Query(object): lookup_type = 'isnull' value = True elif callable(value): + warnings.warn( + "Passing callable arguments to queryset is deprecated.", + PendingDeprecationWarning, stacklevel=2) value = value() elif isinstance(value, ExpressionNode): # If value is a query expression, evaluate it diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index c3b0cda95b..ef2561a05d 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -226,6 +226,8 @@ these changes. loading APIs instead. Several undocumented methods of the ``AppCache`` class will also be removed. +* Passing callable arguments to querysets will no longer be possible. + 2.0 --- diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt index 25b2714d42..4de02c0b6d 100644 --- a/docs/releases/1.7.txt +++ b/docs/releases/1.7.txt @@ -869,3 +869,14 @@ Geo Sitemaps Google has retired support for the Geo Sitemaps format. Hence Django support for Geo Sitemaps is deprecated and will be removed in Django 1.8. + +Passing callable arguments to queryset methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Callable arguments for querysets were an undocumented feature that was +unreliable. It's been deprecated and will be removed in Django 1.9. + +Callable arguments were evaluated when a queryset was constructed rather than +when it was evaluated, thus this feature didn't offer any benefit compared to +evaluating arguments before passing them to queryset and created confusion that +the arguments may have been evaluated at query time. diff --git a/tests/queries/tests.py b/tests/queries/tests.py index 02c7b33480..338ec06921 100644 --- a/tests/queries/tests.py +++ b/tests/queries/tests.py @@ -5,6 +5,7 @@ import datetime from operator import attrgetter import pickle import unittest +import warnings from django.core.exceptions import FieldError from django.db import DatabaseError, connection, connections, DEFAULT_DB_ALIAS @@ -1139,6 +1140,17 @@ class Queries1Tests(BaseQuerysetTest): ['', '', '', ''] ) + def test_callable_args(self): + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + qs = Tag.objects.filter(name__startswith=lambda: 't') + self.assertQuerysetEqual( + qs, + ['', '', '', '', ''] + ) + self.assertEqual(len(w), 1) + self.assertTrue(issubclass(w[0].category, PendingDeprecationWarning)) + class Queries2Tests(TestCase): def setUp(self):