From 6983a1a540a6e6c3bd941fa15ddd8cb49f9ec74e Mon Sep 17 00:00:00 2001 From: Loic Bistuer Date: Fri, 8 Mar 2013 09:15:23 -0500 Subject: [PATCH] Fixed #15363 -- Renamed and normalized to `get_queryset` the methods that return a QuerySet. --- AUTHORS | 2 +- django/contrib/admin/options.py | 31 ++-- .../contrib/admin/templatetags/admin_list.py | 10 +- django/contrib/admin/views/main.py | 39 ++++- django/contrib/auth/admin.py | 2 +- django/contrib/comments/managers.py | 4 +- .../contrib/comments/templatetags/comments.py | 17 +- django/contrib/contenttypes/generic.py | 20 ++- django/contrib/gis/db/models/manager.py | 62 +++---- django/contrib/sites/managers.py | 4 +- django/core/serializers/__init__.py | 2 +- django/db/models/fields/related.py | 46 ++--- django/db/models/manager.py | 84 +++++----- django/db/models/query.py | 14 +- django/forms/models.py | 6 +- django/utils/deprecation.py | 62 +++++++ docs/faq/admin.txt | 2 +- docs/internals/deprecation.txt | 9 + docs/ref/contrib/admin/index.txt | 15 +- docs/ref/models/querysets.txt | 18 +- docs/releases/1.6.txt | 6 + docs/topics/db/managers.txt | 25 +-- docs/topics/db/multi-db.txt | 16 +- tests/admin_changelist/admin.py | 8 +- tests/admin_changelist/models.py | 4 +- tests/admin_changelist/tests.py | 14 +- tests/admin_filters/tests.py | 50 +++--- tests/admin_ordering/tests.py | 20 +-- tests/admin_views/admin.py | 36 ++-- tests/admin_views/customadmin.py | 4 +- tests/admin_views/tests.py | 12 +- tests/admin_widgets/models.py | 4 +- tests/custom_managers/models.py | 10 +- tests/custom_managers_regress/models.py | 4 +- tests/deprecation/__init__.py | 0 tests/deprecation/models.py | 0 tests/deprecation/tests.py | 158 ++++++++++++++++++ tests/fixtures/models.py | 4 +- tests/generic_relations/models.py | 4 +- tests/get_object_or_404/models.py | 4 +- tests/managers_regress/models.py | 12 +- tests/modeladmin/tests.py | 4 +- tests/prefetch_related/models.py | 4 +- tests/proxy_models/models.py | 8 +- tests/queries/models.py | 8 +- tests/reverse_single_related/models.py | 4 +- 46 files changed, 588 insertions(+), 284 deletions(-) create mode 100644 django/utils/deprecation.py create mode 100644 tests/deprecation/__init__.py create mode 100644 tests/deprecation/models.py create mode 100644 tests/deprecation/tests.py diff --git a/AUTHORS b/AUTHORS index c6d7bf0414..35a316d4c2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -98,7 +98,7 @@ answer newbie questions, and generally made Django that much better: Natalia Bidart Mark Biggers Paul Bissex - Loic Bistuer + Loïc Bistuer Simon Blanchard Craig Blaszczyk David Blewett diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 567f7cf990..de7614ff24 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -29,6 +29,7 @@ from django.utils.datastructures import SortedDict from django.utils.html import escape, escapejs from django.utils.safestring import mark_safe from django.utils import six +from django.utils.deprecation import RenameMethodsBase from django.utils.text import capfirst, get_text_list from django.utils.translation import ugettext as _ from django.utils.translation import ungettext @@ -64,7 +65,13 @@ FORMFIELD_FOR_DBFIELD_DEFAULTS = { csrf_protect_m = method_decorator(csrf_protect) -class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): +class RenameBaseModelAdminMethods(forms.MediaDefiningClass, RenameMethodsBase): + renamed_methods = ( + ('queryset', 'get_queryset', PendingDeprecationWarning), + ) + + +class BaseModelAdmin(six.with_metaclass(RenameBaseModelAdminMethods)): """Functionality common to both ModelAdmin and InlineAdmin.""" raw_id_fields = () @@ -239,12 +246,12 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): """ return self.prepopulated_fields - def queryset(self, request): + def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ - qs = self.model._default_manager.get_query_set() + qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: @@ -496,7 +503,7 @@ class ModelAdmin(BaseModelAdmin): returned if no match is found (or the object_id failed validation against the primary key field). """ - queryset = self.queryset(request) + queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) @@ -1008,7 +1015,7 @@ class ModelAdmin(BaseModelAdmin): formset = FormSet(data=request.POST, files=request.FILES, instance=new_object, save_as_new="_saveasnew" in request.POST, - prefix=prefix, queryset=inline.queryset(request)) + prefix=prefix, queryset=inline.get_queryset(request)) formsets.append(formset) if all_valid(formsets) and form_validated: self.save_model(request, new_object, form, False) @@ -1034,7 +1041,7 @@ class ModelAdmin(BaseModelAdmin): if prefixes[prefix] != 1 or not prefix: prefix = "%s-%s" % (prefix, prefixes[prefix]) formset = FormSet(instance=self.model(), prefix=prefix, - queryset=inline.queryset(request)) + queryset=inline.get_queryset(request)) formsets.append(formset) adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)), @@ -1104,7 +1111,7 @@ class ModelAdmin(BaseModelAdmin): prefix = "%s-%s" % (prefix, prefixes[prefix]) formset = FormSet(request.POST, request.FILES, instance=new_object, prefix=prefix, - queryset=inline.queryset(request)) + queryset=inline.get_queryset(request)) formsets.append(formset) @@ -1124,7 +1131,7 @@ class ModelAdmin(BaseModelAdmin): if prefixes[prefix] != 1 or not prefix: prefix = "%s-%s" % (prefix, prefixes[prefix]) formset = FormSet(instance=obj, prefix=prefix, - queryset=inline.queryset(request)) + queryset=inline.get_queryset(request)) formsets.append(formset) adminForm = helpers.AdminForm(form, self.get_fieldsets(request, obj), @@ -1209,7 +1216,7 @@ class ModelAdmin(BaseModelAdmin): if (actions and request.method == 'POST' and 'index' in request.POST and '_save' not in request.POST): if selected: - response = self.response_action(request, queryset=cl.get_query_set(request)) + response = self.response_action(request, queryset=cl.get_queryset(request)) if response: return response else: @@ -1225,7 +1232,7 @@ class ModelAdmin(BaseModelAdmin): helpers.ACTION_CHECKBOX_NAME in request.POST and 'index' not in request.POST and '_save' not in request.POST): if selected: - response = self.response_action(request, queryset=cl.get_query_set(request)) + response = self.response_action(request, queryset=cl.get_queryset(request)) if response: return response else: @@ -1521,8 +1528,8 @@ class InlineModelAdmin(BaseModelAdmin): fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})] - def queryset(self, request): - queryset = super(InlineModelAdmin, self).queryset(request) + def get_queryset(self, request): + queryset = super(InlineModelAdmin, self).get_queryset(request) if not self.has_change_permission(request): queryset = queryset.none() return queryset diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index c08193d238..18a45a006f 100644 --- a/django/contrib/admin/templatetags/admin_list.py +++ b/django/contrib/admin/templatetags/admin_list.py @@ -306,8 +306,8 @@ def date_hierarchy(cl): if not (year_lookup or month_lookup or day_lookup): # select appropriate start level - date_range = cl.query_set.aggregate(first=models.Min(field_name), - last=models.Max(field_name)) + date_range = cl.queryset.aggregate(first=models.Min(field_name), + last=models.Max(field_name)) if date_range['first'] and date_range['last']: if date_range['first'].year == date_range['last'].year: year_lookup = date_range['first'].year @@ -325,7 +325,7 @@ def date_hierarchy(cl): 'choices': [{'title': capfirst(formats.date_format(day, 'MONTH_DAY_FORMAT'))}] } elif year_lookup and month_lookup: - days = cl.query_set.filter(**{year_field: year_lookup, month_field: month_lookup}) + days = cl.queryset.filter(**{year_field: year_lookup, month_field: month_lookup}) days = getattr(days, dates_or_datetimes)(field_name, 'day') return { 'show': True, @@ -339,7 +339,7 @@ def date_hierarchy(cl): } for day in days] } elif year_lookup: - months = cl.query_set.filter(**{year_field: year_lookup}) + months = cl.queryset.filter(**{year_field: year_lookup}) months = getattr(months, dates_or_datetimes)(field_name, 'month') return { 'show': True, @@ -353,7 +353,7 @@ def date_hierarchy(cl): } for month in months] } else: - years = getattr(cl.query_set, dates_or_datetimes)(field_name, 'year') + years = getattr(cl.queryset, dates_or_datetimes)(field_name, 'year') return { 'show': True, 'choices': [{ diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 8bda323d83..b7bf85ef9d 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -1,4 +1,5 @@ import operator +import warnings from functools import reduce from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured @@ -6,7 +7,9 @@ from django.core.paginator import InvalidPage from django.core.urlresolvers import reverse from django.db import models from django.db.models.fields import FieldDoesNotExist +from django.utils import six from django.utils.datastructures import SortedDict +from django.utils.deprecation import RenameMethodsBase from django.utils.encoding import force_str, force_text from django.utils.translation import ugettext, ugettext_lazy from django.utils.http import urlencode @@ -33,14 +36,20 @@ IGNORED_PARAMS = ( EMPTY_CHANGELIST_VALUE = ugettext_lazy('(None)') -class ChangeList(object): +class RenameChangeListMethods(RenameMethodsBase): + renamed_methods = ( + ('get_query_set', 'get_queryset', PendingDeprecationWarning), + ) + + +class ChangeList(six.with_metaclass(RenameChangeListMethods)): def __init__(self, request, model, list_display, list_display_links, list_filter, date_hierarchy, search_fields, list_select_related, list_per_page, list_max_show_all, list_editable, model_admin): self.model = model self.opts = model._meta self.lookup_opts = self.opts - self.root_query_set = model_admin.queryset(request) + self.root_queryset = model_admin.get_queryset(request) self.list_display = list_display self.list_display_links = list_display_links self.list_filter = list_filter @@ -70,7 +79,7 @@ class ChangeList(object): else: self.list_editable = list_editable self.query = request.GET.get(SEARCH_VAR, '') - self.query_set = self.get_query_set(request) + self.queryset = self.get_queryset(request) self.get_results(request) if self.is_popup: title = ugettext('Select %s') @@ -79,6 +88,20 @@ class ChangeList(object): self.title = title % force_text(self.opts.verbose_name) self.pk_attname = self.lookup_opts.pk.attname + @property + def root_query_set(self): + warnings.warn("`ChangeList.root_query_set` is deprecated, " + "use `root_queryset` instead.", + PendingDeprecationWarning, 2) + return self.root_queryset + + @property + def query_set(self): + warnings.warn("`ChangeList.query_set` is deprecated, " + "use `queryset` instead.", + PendingDeprecationWarning, 2) + return self.queryset + def get_filters_params(self, params=None): """ Returns all params except IGNORED_PARAMS @@ -169,7 +192,7 @@ class ChangeList(object): return '?%s' % urlencode(sorted(p.items())) def get_results(self, request): - paginator = self.model_admin.get_paginator(request, self.query_set, self.list_per_page) + paginator = self.model_admin.get_paginator(request, self.queryset, self.list_per_page) # Get the number of objects, with admin filters applied. result_count = paginator.count @@ -178,7 +201,7 @@ class ChangeList(object): # full_result_count is equal to paginator.count if no filters # were applied if self.get_filters_params(): - full_result_count = self.root_query_set.count() + full_result_count = self.root_queryset.count() else: full_result_count = result_count can_show_all = result_count <= self.list_max_show_all @@ -186,7 +209,7 @@ class ChangeList(object): # Get the list of objects to display on this page. if (self.show_all and can_show_all) or not multi_page: - result_list = self.query_set._clone() + result_list = self.queryset._clone() else: try: result_list = paginator.page(self.page_num+1).object_list @@ -304,13 +327,13 @@ class ChangeList(object): ordering_fields[idx] = 'desc' if pfx == '-' else 'asc' return ordering_fields - def get_query_set(self, request): + def get_queryset(self, request): # First, we collect all the declared list filters. (self.filter_specs, self.has_filters, remaining_lookup_params, use_distinct) = self.get_filters(request) # Then, we let every list filter modify the queryset to its liking. - qs = self.root_query_set + qs = self.root_queryset for filter_spec in self.filter_specs: new_qs = filter_spec.queryset(request, qs) if new_qs is not None: diff --git a/django/contrib/auth/admin.py b/django/contrib/auth/admin.py index 7b816674d3..0abc361a41 100644 --- a/django/contrib/auth/admin.py +++ b/django/contrib/auth/admin.py @@ -118,7 +118,7 @@ class UserAdmin(admin.ModelAdmin): def user_change_password(self, request, id, form_url=''): if not self.has_change_permission(request): raise PermissionDenied - user = get_object_or_404(self.queryset(request), pk=id) + user = get_object_or_404(self.get_queryset(request), pk=id) if request.method == 'POST': form = self.change_password_form(user, request.POST) if form.is_valid(): diff --git a/django/contrib/comments/managers.py b/django/contrib/comments/managers.py index bc0fc5f332..656200437b 100644 --- a/django/contrib/comments/managers.py +++ b/django/contrib/comments/managers.py @@ -8,7 +8,7 @@ class CommentManager(models.Manager): """ QuerySet for all comments currently in the moderation queue. """ - return self.get_query_set().filter(is_public=False, is_removed=False) + return self.get_queryset().filter(is_public=False, is_removed=False) def for_model(self, model): """ @@ -16,7 +16,7 @@ class CommentManager(models.Manager): a class). """ ct = ContentType.objects.get_for_model(model) - qs = self.get_query_set().filter(content_type=ct) + qs = self.get_queryset().filter(content_type=ct) if isinstance(model, models.Model): qs = qs.filter(object_pk=force_text(model._get_pk_val())) return qs diff --git a/django/contrib/comments/templatetags/comments.py b/django/contrib/comments/templatetags/comments.py index b5266d9bb3..d8eed76ad6 100644 --- a/django/contrib/comments/templatetags/comments.py +++ b/django/contrib/comments/templatetags/comments.py @@ -3,11 +3,20 @@ from django.template.loader import render_to_string from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.contrib import comments +from django.utils import six +from django.utils.deprecation import RenameMethodsBase from django.utils.encoding import smart_text register = template.Library() -class BaseCommentNode(template.Node): + +class RenameBaseCommentNodeMethods(RenameMethodsBase): + renamed_methods = ( + ('get_query_set', 'get_queryset', PendingDeprecationWarning), + ) + + +class BaseCommentNode(six.with_metaclass(RenameBaseCommentNodeMethods, template.Node)): """ Base helper class (abstract) for handling the get_comment_* template tags. Looks a bit strange, but the subclasses below should make this a bit more @@ -64,11 +73,11 @@ class BaseCommentNode(template.Node): self.comment = comment def render(self, context): - qs = self.get_query_set(context) + qs = self.get_queryset(context) context[self.as_varname] = self.get_context_value_from_queryset(context, qs) return '' - def get_query_set(self, context): + def get_queryset(self, context): ctype, object_pk = self.get_target_ctype_pk(context) if not object_pk: return self.comment_model.objects.none() @@ -205,7 +214,7 @@ class RenderCommentListNode(CommentListNode): "comments/%s/list.html" % ctype.app_label, "comments/list.html" ] - qs = self.get_query_set(context) + qs = self.get_queryset(context) context.push() liststr = render_to_string(template_search_list, { "comment_list" : self.get_context_value_from_queryset(context, qs) diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py index 20ff7042bc..fdb05a626a 100644 --- a/django/contrib/contenttypes/generic.py +++ b/django/contrib/contenttypes/generic.py @@ -16,10 +16,18 @@ from django.forms import ModelForm from django.forms.models import BaseModelFormSet, modelformset_factory, save_instance from django.contrib.admin.options import InlineModelAdmin, flatten_fieldsets from django.contrib.contenttypes.models import ContentType +from django.utils import six +from django.utils.deprecation import RenameMethodsBase from django.utils.encoding import smart_text -class GenericForeignKey(object): +class RenameGenericForeignKeyMethods(RenameMethodsBase): + renamed_methods = ( + ('get_prefetch_query_set', 'get_prefetch_queryset', PendingDeprecationWarning), + ) + + +class GenericForeignKey(six.with_metaclass(RenameGenericForeignKeyMethods)): """ Provides a generic relation to any object through content-type/object-id fields. @@ -60,7 +68,7 @@ class GenericForeignKey(object): # This should never happen. I love comments like this, don't you? raise Exception("Impossible arguments to GFK.get_content_type!") - def get_prefetch_query_set(self, instances): + def get_prefetch_queryset(self, instances): # For efficiency, group the instances by content type and then do one # query per model fk_dict = defaultdict(set) @@ -316,21 +324,21 @@ def create_generic_related_manager(superclass): '%s__exact' % object_id_field_name: instance._get_pk_val(), } - def get_query_set(self): + def get_queryset(self): try: return self.instance._prefetched_objects_cache[self.prefetch_cache_name] except (AttributeError, KeyError): db = self._db or router.db_for_read(self.model, instance=self.instance) - return super(GenericRelatedObjectManager, self).get_query_set().using(db).filter(**self.core_filters) + return super(GenericRelatedObjectManager, self).get_queryset().using(db).filter(**self.core_filters) - def get_prefetch_query_set(self, instances): + def get_prefetch_queryset(self, instances): db = self._db or router.db_for_read(self.model, instance=instances[0]) query = { '%s__pk' % self.content_type_field_name: self.content_type.id, '%s__in' % self.object_id_field_name: set(obj._get_pk_val() for obj in instances) } - qs = super(GenericRelatedObjectManager, self).get_query_set().using(db).filter(**query) + qs = super(GenericRelatedObjectManager, self).get_queryset().using(db).filter(**query) # We (possibly) need to convert object IDs to the type of the # instances' PK in order to match up instances: object_id_converter = instances[0]._meta.pk.to_python diff --git a/django/contrib/gis/db/models/manager.py b/django/contrib/gis/db/models/manager.py index 61fb82132b..aa57e3a507 100644 --- a/django/contrib/gis/db/models/manager.py +++ b/django/contrib/gis/db/models/manager.py @@ -9,95 +9,95 @@ class GeoManager(Manager): # properly. use_for_related_fields = True - def get_query_set(self): + def get_queryset(self): return GeoQuerySet(self.model, using=self._db) def area(self, *args, **kwargs): - return self.get_query_set().area(*args, **kwargs) + return self.get_queryset().area(*args, **kwargs) def centroid(self, *args, **kwargs): - return self.get_query_set().centroid(*args, **kwargs) + return self.get_queryset().centroid(*args, **kwargs) def collect(self, *args, **kwargs): - return self.get_query_set().collect(*args, **kwargs) + return self.get_queryset().collect(*args, **kwargs) def difference(self, *args, **kwargs): - return self.get_query_set().difference(*args, **kwargs) + return self.get_queryset().difference(*args, **kwargs) def distance(self, *args, **kwargs): - return self.get_query_set().distance(*args, **kwargs) + return self.get_queryset().distance(*args, **kwargs) def envelope(self, *args, **kwargs): - return self.get_query_set().envelope(*args, **kwargs) + return self.get_queryset().envelope(*args, **kwargs) def extent(self, *args, **kwargs): - return self.get_query_set().extent(*args, **kwargs) + return self.get_queryset().extent(*args, **kwargs) def extent3d(self, *args, **kwargs): - return self.get_query_set().extent3d(*args, **kwargs) + return self.get_queryset().extent3d(*args, **kwargs) def force_rhr(self, *args, **kwargs): - return self.get_query_set().force_rhr(*args, **kwargs) + return self.get_queryset().force_rhr(*args, **kwargs) def geohash(self, *args, **kwargs): - return self.get_query_set().geohash(*args, **kwargs) + return self.get_queryset().geohash(*args, **kwargs) def geojson(self, *args, **kwargs): - return self.get_query_set().geojson(*args, **kwargs) + return self.get_queryset().geojson(*args, **kwargs) def gml(self, *args, **kwargs): - return self.get_query_set().gml(*args, **kwargs) + return self.get_queryset().gml(*args, **kwargs) def intersection(self, *args, **kwargs): - return self.get_query_set().intersection(*args, **kwargs) + return self.get_queryset().intersection(*args, **kwargs) def kml(self, *args, **kwargs): - return self.get_query_set().kml(*args, **kwargs) + return self.get_queryset().kml(*args, **kwargs) def length(self, *args, **kwargs): - return self.get_query_set().length(*args, **kwargs) + return self.get_queryset().length(*args, **kwargs) def make_line(self, *args, **kwargs): - return self.get_query_set().make_line(*args, **kwargs) + return self.get_queryset().make_line(*args, **kwargs) def mem_size(self, *args, **kwargs): - return self.get_query_set().mem_size(*args, **kwargs) + return self.get_queryset().mem_size(*args, **kwargs) def num_geom(self, *args, **kwargs): - return self.get_query_set().num_geom(*args, **kwargs) + return self.get_queryset().num_geom(*args, **kwargs) def num_points(self, *args, **kwargs): - return self.get_query_set().num_points(*args, **kwargs) + return self.get_queryset().num_points(*args, **kwargs) def perimeter(self, *args, **kwargs): - return self.get_query_set().perimeter(*args, **kwargs) + return self.get_queryset().perimeter(*args, **kwargs) def point_on_surface(self, *args, **kwargs): - return self.get_query_set().point_on_surface(*args, **kwargs) + return self.get_queryset().point_on_surface(*args, **kwargs) def reverse_geom(self, *args, **kwargs): - return self.get_query_set().reverse_geom(*args, **kwargs) + return self.get_queryset().reverse_geom(*args, **kwargs) def scale(self, *args, **kwargs): - return self.get_query_set().scale(*args, **kwargs) + return self.get_queryset().scale(*args, **kwargs) def snap_to_grid(self, *args, **kwargs): - return self.get_query_set().snap_to_grid(*args, **kwargs) + return self.get_queryset().snap_to_grid(*args, **kwargs) def svg(self, *args, **kwargs): - return self.get_query_set().svg(*args, **kwargs) + return self.get_queryset().svg(*args, **kwargs) def sym_difference(self, *args, **kwargs): - return self.get_query_set().sym_difference(*args, **kwargs) + return self.get_queryset().sym_difference(*args, **kwargs) def transform(self, *args, **kwargs): - return self.get_query_set().transform(*args, **kwargs) + return self.get_queryset().transform(*args, **kwargs) def translate(self, *args, **kwargs): - return self.get_query_set().translate(*args, **kwargs) + return self.get_queryset().translate(*args, **kwargs) def union(self, *args, **kwargs): - return self.get_query_set().union(*args, **kwargs) + return self.get_queryset().union(*args, **kwargs) def unionagg(self, *args, **kwargs): - return self.get_query_set().unionagg(*args, **kwargs) + return self.get_queryset().unionagg(*args, **kwargs) diff --git a/django/contrib/sites/managers.py b/django/contrib/sites/managers.py index 3df485a040..becb35b404 100644 --- a/django/contrib/sites/managers.py +++ b/django/contrib/sites/managers.py @@ -35,7 +35,7 @@ class CurrentSiteManager(models.Manager): (self.__class__.__name__, self.__field_name, self.model._meta.object_name)) self.__is_validated = True - def get_query_set(self): + def get_queryset(self): if not self.__is_validated: self._validate_field_name() - return super(CurrentSiteManager, self).get_query_set().filter(**{self.__field_name + '__id__exact': settings.SITE_ID}) + return super(CurrentSiteManager, self).get_queryset().filter(**{self.__field_name + '__id__exact': settings.SITE_ID}) diff --git a/django/core/serializers/__init__.py b/django/core/serializers/__init__.py index cf7e66190f..c48050415d 100644 --- a/django/core/serializers/__init__.py +++ b/django/core/serializers/__init__.py @@ -4,7 +4,7 @@ Interfaces for serializing Django objects. Usage:: from django.core import serializers - json = serializers.serialize("json", some_query_set) + json = serializers.serialize("json", some_queryset) objects = list(serializers.deserialize("json", json)) To add your own serializers, use the SERIALIZATION_MODULES setting:: diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index 399d16600c..3b47eb86bb 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -11,6 +11,7 @@ from django.db.models.query_utils import QueryWrapper from django.db.models.deletion import CASCADE from django.utils.encoding import smart_text from django.utils import six +from django.utils.deprecation import RenameMethodsBase from django.utils.translation import ugettext_lazy as _, string_concat from django.utils.functional import curry, cached_property from django.core import exceptions @@ -225,7 +226,14 @@ class RelatedField(object): return self.rel.related_name or self.opts.model_name -class SingleRelatedObjectDescriptor(object): +class RenameRelatedObjectDescriptorMethods(RenameMethodsBase): + renamed_methods = ( + ('get_query_set', 'get_queryset', PendingDeprecationWarning), + ('get_prefetch_query_set', 'get_prefetch_queryset', PendingDeprecationWarning), + ) + + +class SingleRelatedObjectDescriptor(six.with_metaclass(RenameRelatedObjectDescriptorMethods)): # This class provides the functionality that makes the related-object # managers available as attributes on a model class, for fields that have # a single "remote" value, on the class pointed to by a related field. @@ -238,16 +246,16 @@ class SingleRelatedObjectDescriptor(object): def is_cached(self, instance): return hasattr(instance, self.cache_name) - def get_query_set(self, **db_hints): + def get_queryset(self, **db_hints): db = router.db_for_read(self.related.model, **db_hints) return self.related.model._base_manager.using(db) - def get_prefetch_query_set(self, instances): + def get_prefetch_queryset(self, instances): rel_obj_attr = attrgetter(self.related.field.attname) instance_attr = lambda obj: obj._get_pk_val() instances_dict = dict((instance_attr(inst), inst) for inst in instances) params = {'%s__pk__in' % self.related.field.name: list(instances_dict)} - qs = self.get_query_set(instance=instances[0]).filter(**params) + qs = self.get_queryset(instance=instances[0]).filter(**params) # Since we're going to assign directly in the cache, # we must manage the reverse relation cache manually. rel_obj_cache_name = self.related.field.get_cache_name() @@ -268,7 +276,7 @@ class SingleRelatedObjectDescriptor(object): else: params = {'%s__pk' % self.related.field.name: related_pk} try: - rel_obj = self.get_query_set(instance=instance).get(**params) + rel_obj = self.get_queryset(instance=instance).get(**params) except self.related.model.DoesNotExist: rel_obj = None else: @@ -321,7 +329,7 @@ class SingleRelatedObjectDescriptor(object): setattr(value, self.related.field.get_cache_name(), instance) -class ReverseSingleRelatedObjectDescriptor(object): +class ReverseSingleRelatedObjectDescriptor(six.with_metaclass(RenameRelatedObjectDescriptorMethods)): # This class provides the functionality that makes the related-object # managers available as attributes on a model class, for fields that have # a single "remote" value, on the class that defines the related field. @@ -334,7 +342,7 @@ class ReverseSingleRelatedObjectDescriptor(object): def is_cached(self, instance): return hasattr(instance, self.cache_name) - def get_query_set(self, **db_hints): + def get_queryset(self, **db_hints): db = router.db_for_read(self.field.rel.to, **db_hints) rel_mgr = self.field.rel.to._default_manager # If the related manager indicates that it should be used for @@ -344,7 +352,7 @@ class ReverseSingleRelatedObjectDescriptor(object): else: return QuerySet(self.field.rel.to).using(db) - def get_prefetch_query_set(self, instances): + def get_prefetch_queryset(self, instances): other_field = self.field.rel.get_related_field() rel_obj_attr = attrgetter(other_field.attname) instance_attr = attrgetter(self.field.attname) @@ -353,7 +361,7 @@ class ReverseSingleRelatedObjectDescriptor(object): params = {'%s__pk__in' % self.field.rel.field_name: list(instances_dict)} else: params = {'%s__in' % self.field.rel.field_name: list(instances_dict)} - qs = self.get_query_set(instance=instances[0]).filter(**params) + qs = self.get_queryset(instance=instances[0]).filter(**params) # Since we're going to assign directly in the cache, # we must manage the reverse relation cache manually. if not self.field.rel.multiple: @@ -378,7 +386,7 @@ class ReverseSingleRelatedObjectDescriptor(object): params = {'%s__%s' % (self.field.rel.field_name, other_field.rel.field_name): val} else: params = {'%s__exact' % self.field.rel.field_name: val} - qs = self.get_query_set(instance=instance) + qs = self.get_queryset(instance=instance) # Assuming the database enforces foreign keys, this won't fail. rel_obj = qs.get(**params) if not self.field.rel.multiple: @@ -490,26 +498,26 @@ class ForeignRelatedObjectsDescriptor(object): } self.model = rel_model - def get_query_set(self): + def get_queryset(self): try: return self.instance._prefetched_objects_cache[rel_field.related_query_name()] except (AttributeError, KeyError): db = self._db or router.db_for_read(self.model, instance=self.instance) - qs = super(RelatedManager, self).get_query_set().using(db).filter(**self.core_filters) + qs = super(RelatedManager, self).get_queryset().using(db).filter(**self.core_filters) val = getattr(self.instance, attname) if val is None or val == '' and connections[db].features.interprets_empty_strings_as_nulls: return qs.none() qs._known_related_objects = {rel_field: {self.instance.pk: self.instance}} return qs - def get_prefetch_query_set(self, instances): + def get_prefetch_queryset(self, instances): rel_obj_attr = attrgetter(rel_field.attname) instance_attr = attrgetter(attname) instances_dict = dict((instance_attr(inst), inst) for inst in instances) db = self._db or router.db_for_read(self.model, instance=instances[0]) query = {'%s__%s__in' % (rel_field.name, attname): list(instances_dict)} - qs = super(RelatedManager, self).get_query_set().using(db).filter(**query) - # Since we just bypassed this class' get_query_set(), we must manage + qs = super(RelatedManager, self).get_queryset().using(db).filter(**query) + # Since we just bypassed this class' get_queryset(), we must manage # the reverse relation manually. for rel_obj in qs: instance = instances_dict[rel_obj_attr(rel_obj)] @@ -603,20 +611,20 @@ def create_many_related_manager(superclass, rel): else: return obj.pk - def get_query_set(self): + def get_queryset(self): try: return self.instance._prefetched_objects_cache[self.prefetch_cache_name] except (AttributeError, KeyError): db = self._db or router.db_for_read(self.instance.__class__, instance=self.instance) - return super(ManyRelatedManager, self).get_query_set().using(db)._next_is_sticky().filter(**self.core_filters) + return super(ManyRelatedManager, self).get_queryset().using(db)._next_is_sticky().filter(**self.core_filters) - def get_prefetch_query_set(self, instances): + def get_prefetch_queryset(self, instances): instance = instances[0] from django.db import connections db = self._db or router.db_for_read(instance.__class__, instance=instance) query = {'%s__pk__in' % self.query_field_name: set(obj._get_pk_val() for obj in instances)} - qs = super(ManyRelatedManager, self).get_query_set().using(db)._next_is_sticky().filter(**query) + qs = super(ManyRelatedManager, self).get_queryset().using(db)._next_is_sticky().filter(**query) # M2M: need to annotate the query in order to get the primary model # that the secondary model was actually related to. We know that diff --git a/django/db/models/manager.py b/django/db/models/manager.py index b1f2e10735..43a8264f11 100644 --- a/django/db/models/manager.py +++ b/django/db/models/manager.py @@ -3,7 +3,8 @@ from django.db import router from django.db.models.query import QuerySet, insert_query, RawQuerySet from django.db.models import signals from django.db.models.fields import FieldDoesNotExist - +from django.utils import six +from django.utils.deprecation import RenameMethodsBase def ensure_default_manager(sender, **kwargs): """ @@ -47,7 +48,14 @@ def ensure_default_manager(sender, **kwargs): signals.class_prepared.connect(ensure_default_manager) -class Manager(object): +class RenameManagerMethods(RenameMethodsBase): + renamed_methods = ( + ('get_query_set', 'get_queryset', PendingDeprecationWarning), + ('get_prefetch_query_set', 'get_prefetch_queryset', PendingDeprecationWarning), + ) + + +class Manager(six.with_metaclass(RenameManagerMethods)): # Tracks each time a Manager instance is created. Used to retain order. creation_counter = 0 @@ -112,113 +120,113 @@ class Manager(object): # PROXIES TO QUERYSET # ####################### - def get_query_set(self): + def get_queryset(self): """Returns a new QuerySet object. Subclasses can override this method to easily customize the behavior of the Manager. """ return QuerySet(self.model, using=self._db) def none(self): - return self.get_query_set().none() + return self.get_queryset().none() def all(self): - return self.get_query_set() + return self.get_queryset() def count(self): - return self.get_query_set().count() + return self.get_queryset().count() def dates(self, *args, **kwargs): - return self.get_query_set().dates(*args, **kwargs) + return self.get_queryset().dates(*args, **kwargs) def datetimes(self, *args, **kwargs): - return self.get_query_set().datetimes(*args, **kwargs) + return self.get_queryset().datetimes(*args, **kwargs) def distinct(self, *args, **kwargs): - return self.get_query_set().distinct(*args, **kwargs) + return self.get_queryset().distinct(*args, **kwargs) def extra(self, *args, **kwargs): - return self.get_query_set().extra(*args, **kwargs) + return self.get_queryset().extra(*args, **kwargs) def get(self, *args, **kwargs): - return self.get_query_set().get(*args, **kwargs) + return self.get_queryset().get(*args, **kwargs) def get_or_create(self, **kwargs): - return self.get_query_set().get_or_create(**kwargs) + return self.get_queryset().get_or_create(**kwargs) def create(self, **kwargs): - return self.get_query_set().create(**kwargs) + return self.get_queryset().create(**kwargs) def bulk_create(self, *args, **kwargs): - return self.get_query_set().bulk_create(*args, **kwargs) + return self.get_queryset().bulk_create(*args, **kwargs) def filter(self, *args, **kwargs): - return self.get_query_set().filter(*args, **kwargs) + return self.get_queryset().filter(*args, **kwargs) def aggregate(self, *args, **kwargs): - return self.get_query_set().aggregate(*args, **kwargs) + return self.get_queryset().aggregate(*args, **kwargs) def annotate(self, *args, **kwargs): - return self.get_query_set().annotate(*args, **kwargs) + return self.get_queryset().annotate(*args, **kwargs) def complex_filter(self, *args, **kwargs): - return self.get_query_set().complex_filter(*args, **kwargs) + return self.get_queryset().complex_filter(*args, **kwargs) def exclude(self, *args, **kwargs): - return self.get_query_set().exclude(*args, **kwargs) + return self.get_queryset().exclude(*args, **kwargs) def in_bulk(self, *args, **kwargs): - return self.get_query_set().in_bulk(*args, **kwargs) + return self.get_queryset().in_bulk(*args, **kwargs) def iterator(self, *args, **kwargs): - return self.get_query_set().iterator(*args, **kwargs) + return self.get_queryset().iterator(*args, **kwargs) def earliest(self, *args, **kwargs): - return self.get_query_set().earliest(*args, **kwargs) + return self.get_queryset().earliest(*args, **kwargs) def latest(self, *args, **kwargs): - return self.get_query_set().latest(*args, **kwargs) + return self.get_queryset().latest(*args, **kwargs) def order_by(self, *args, **kwargs): - return self.get_query_set().order_by(*args, **kwargs) + return self.get_queryset().order_by(*args, **kwargs) def select_for_update(self, *args, **kwargs): - return self.get_query_set().select_for_update(*args, **kwargs) + return self.get_queryset().select_for_update(*args, **kwargs) def select_related(self, *args, **kwargs): - return self.get_query_set().select_related(*args, **kwargs) + return self.get_queryset().select_related(*args, **kwargs) def prefetch_related(self, *args, **kwargs): - return self.get_query_set().prefetch_related(*args, **kwargs) + return self.get_queryset().prefetch_related(*args, **kwargs) def values(self, *args, **kwargs): - return self.get_query_set().values(*args, **kwargs) + return self.get_queryset().values(*args, **kwargs) def values_list(self, *args, **kwargs): - return self.get_query_set().values_list(*args, **kwargs) + return self.get_queryset().values_list(*args, **kwargs) def update(self, *args, **kwargs): - return self.get_query_set().update(*args, **kwargs) + return self.get_queryset().update(*args, **kwargs) def reverse(self, *args, **kwargs): - return self.get_query_set().reverse(*args, **kwargs) + return self.get_queryset().reverse(*args, **kwargs) def defer(self, *args, **kwargs): - return self.get_query_set().defer(*args, **kwargs) + return self.get_queryset().defer(*args, **kwargs) def only(self, *args, **kwargs): - return self.get_query_set().only(*args, **kwargs) + return self.get_queryset().only(*args, **kwargs) def using(self, *args, **kwargs): - return self.get_query_set().using(*args, **kwargs) + return self.get_queryset().using(*args, **kwargs) def exists(self, *args, **kwargs): - return self.get_query_set().exists(*args, **kwargs) + return self.get_queryset().exists(*args, **kwargs) def _insert(self, objs, fields, **kwargs): return insert_query(self.model, objs, fields, **kwargs) def _update(self, values, **kwargs): - return self.get_query_set()._update(values, **kwargs) + return self.get_queryset()._update(values, **kwargs) def raw(self, raw_query, params=None, *args, **kwargs): return RawQuerySet(raw_query=raw_query, model=self.model, params=params, using=self._db, *args, **kwargs) @@ -265,5 +273,5 @@ class EmptyManager(Manager): super(EmptyManager, self).__init__() self.model = model - def get_query_set(self): - return super(EmptyManager, self).get_query_set().none() + def get_queryset(self): + return super(EmptyManager, self).get_queryset().none() diff --git a/django/db/models/query.py b/django/db/models/query.py index ec35f8aba3..30be30ca43 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -1733,9 +1733,9 @@ def prefetch_related_objects(result_cache, related_lookups): def get_prefetcher(instance, attr): """ For the attribute 'attr' on the given instance, finds - an object that has a get_prefetch_query_set(). + an object that has a get_prefetch_queryset(). Returns a 4 tuple containing: - (the object with get_prefetch_query_set (or None), + (the object with get_prefetch_queryset (or None), the descriptor object representing this relationship (or None), a boolean that is False if the attribute was not found at all, a boolean that is True if the attribute has already been fetched) @@ -1758,8 +1758,8 @@ def get_prefetcher(instance, attr): attr_found = True if rel_obj_descriptor: # singly related object, descriptor object has the - # get_prefetch_query_set() method. - if hasattr(rel_obj_descriptor, 'get_prefetch_query_set'): + # get_prefetch_queryset() method. + if hasattr(rel_obj_descriptor, 'get_prefetch_queryset'): prefetcher = rel_obj_descriptor if rel_obj_descriptor.is_cached(instance): is_fetched = True @@ -1768,7 +1768,7 @@ def get_prefetcher(instance, attr): # the attribute on the instance rather than the class to # support many related managers rel_obj = getattr(instance, attr) - if hasattr(rel_obj, 'get_prefetch_query_set'): + if hasattr(rel_obj, 'get_prefetch_queryset'): prefetcher = rel_obj return prefetcher, rel_obj_descriptor, attr_found, is_fetched @@ -1784,7 +1784,7 @@ def prefetch_one_level(instances, prefetcher, attname): prefetches that must be done due to prefetch_related lookups found from default managers. """ - # prefetcher must have a method get_prefetch_query_set() which takes a list + # prefetcher must have a method get_prefetch_queryset() which takes a list # of instances, and returns a tuple: # (queryset of instances of self.model that are related to passed in instances, @@ -1797,7 +1797,7 @@ def prefetch_one_level(instances, prefetcher, attname): # in a dictionary. rel_qs, rel_obj_attr, instance_attr, single, cache_name =\ - prefetcher.get_prefetch_query_set(instances) + prefetcher.get_prefetch_queryset(instances) # We have to handle the possibility that the default manager itself added # prefetch_related lookups to the QuerySet we just got back. We don't want to # trigger the prefetch_related functionality by evaluating the query. diff --git a/django/forms/models.py b/django/forms/models.py index 7609bb7227..272f1ddee6 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -478,7 +478,7 @@ class BaseModelFormSet(BaseFormSet): if self.queryset is not None: qs = self.queryset else: - qs = self.model._default_manager.get_query_set() + qs = self.model._default_manager.get_queryset() # If the queryset isn't already ordered we need to add an # artificial ordering here to make sure that all formsets @@ -668,9 +668,9 @@ class BaseModelFormSet(BaseFormSet): except IndexError: pk_value = None if isinstance(pk, OneToOneField) or isinstance(pk, ForeignKey): - qs = pk.rel.to._default_manager.get_query_set() + qs = pk.rel.to._default_manager.get_queryset() else: - qs = self.model._default_manager.get_query_set() + qs = self.model._default_manager.get_queryset() qs = qs.using(form.instance._state.db) if form._meta.widgets: widget = form._meta.widgets.get(self._pk_field.name, HiddenInput) diff --git a/django/utils/deprecation.py b/django/utils/deprecation.py new file mode 100644 index 0000000000..edbb5ca5ea --- /dev/null +++ b/django/utils/deprecation.py @@ -0,0 +1,62 @@ +import inspect +import warnings + + +class warn_about_renamed_method(object): + def __init__(self, class_name, old_method_name, new_method_name, deprecation_warning): + self.class_name = class_name + self.old_method_name = old_method_name + self.new_method_name = new_method_name + self.deprecation_warning = deprecation_warning + + def __call__(self, f): + def wrapped(*args, **kwargs): + warnings.warn( + "`%s.%s` is deprecated, use `%s` instead." % + (self.class_name, self.old_method_name, self.new_method_name), + self.deprecation_warning, 2) + return f(*args, **kwargs) + return wrapped + + +class RenameMethodsBase(type): + """ + Handles the deprecation paths when renaming a method. + + It does the following: + 1) Define the new method if missing and complain about it. + 2) Define the old method if missing. + 3) Complain whenever an old method is called. + + See #15363 for more details. + """ + + renamed_methods = () + + def __new__(cls, name, bases, attrs): + new_class = super(RenameMethodsBase, cls).__new__(cls, name, bases, attrs) + + for base in inspect.getmro(new_class): + class_name = base.__name__ + for renamed_method in cls.renamed_methods: + old_method_name = renamed_method[0] + old_method = base.__dict__.get(old_method_name) + new_method_name = renamed_method[1] + new_method = base.__dict__.get(new_method_name) + deprecation_warning = renamed_method[2] + wrapper = warn_about_renamed_method(class_name, *renamed_method) + + # Define the new method if missing and complain about it + if not new_method and old_method: + warnings.warn( + "`%s.%s` method should be renamed `%s`." % + (class_name, old_method_name, new_method_name), + deprecation_warning, 2) + setattr(base, new_method_name, old_method) + setattr(base, old_method_name, wrapper(old_method)) + + # Define the old method as a wrapped call to the new method. + if not old_method and new_method: + setattr(base, old_method_name, wrapper(new_method)) + + return new_class diff --git a/docs/faq/admin.txt b/docs/faq/admin.txt index 30d452cbe2..1d9a7c7427 100644 --- a/docs/faq/admin.txt +++ b/docs/faq/admin.txt @@ -49,7 +49,7 @@ How do I limit admin access so that objects can only be edited by the users who The :class:`~django.contrib.admin.ModelAdmin` class also provides customization hooks that allow you to control the visibility and editability of objects in the admin. Using the same trick of extracting the user from the request, the -:meth:`~django.contrib.admin.ModelAdmin.queryset` and +:meth:`~django.contrib.admin.ModelAdmin.get_queryset` and :meth:`~django.contrib.admin.ModelAdmin.has_change_permission` can be used to control the visibility and editability of objects in the admin. diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 3a9cbd195d..b5173af298 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -341,6 +341,15 @@ these changes. * The private API ``django.db.close_connection`` will be removed. +* Remove the backward compatible shims introduced to rename ``get_query_set`` + and similar queryset methods. This affects the following classes: + ``BaseModelAdmin``, ``ChangeList``, ``BaseCommentNode``, + ``GenericForeignKey``, ``Manager``, ``SingleRelatedObjectDescriptor`` and + ``ReverseSingleRelatedObjectDescriptor``. + +* Remove the backward compatible shims introduced to rename the attributes + ``ChangeList.root_query_set`` and ``ChangeList.query_set``. + 2.0 --- diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 9a0f3ca7f8..ae2ee44601 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -703,7 +703,7 @@ subclass:: Only show the lookups if there actually is anyone born in the corresponding decades. """ - qs = model_admin.queryset(request) + qs = model_admin.get_queryset(request) if qs.filter(birthday__gte=date(1980, 1, 1), birthday__lte=date(1989, 12, 31)).exists(): yield ('80s', _('in the eighties')) @@ -1326,20 +1326,23 @@ templates used by the :class:`ModelAdmin` views: be interpreted as meaning that the current user is not permitted to delete any object of this type). -.. method:: ModelAdmin.queryset(self, request) +.. method:: ModelAdmin.get_queryset(self, request) - The ``queryset`` method on a ``ModelAdmin`` returns a + The ``get_queryset`` method on a ``ModelAdmin`` returns a :class:`~django.db.models.query.QuerySet` of all model instances that can be edited by the admin site. One use case for overriding this method is to show objects owned by the logged-in user:: class MyModelAdmin(admin.ModelAdmin): - def queryset(self, request): - qs = super(MyModelAdmin, self).queryset(request) + def get_queryset(self, request): + qs = super(MyModelAdmin, self).get_queryset(request) if request.user.is_superuser: return qs return qs.filter(author=request.user) + .. versionchanged:: 1.6 + The ``get_queryset`` method was previously named ``queryset``. + .. method:: ModelAdmin.message_user(request, message, level=messages.INFO, extra_tags='', fail_silently=False) Sends a message to the user using the :mod:`django.contrib.messages` @@ -1549,7 +1552,7 @@ adds some of its own (the shared features are actually defined in the - :attr:`~ModelAdmin.filter_vertical` - :attr:`~ModelAdmin.ordering` - :attr:`~ModelAdmin.prepopulated_fields` -- :meth:`~ModelAdmin.queryset` +- :meth:`~ModelAdmin.get_queryset` - :attr:`~ModelAdmin.radio_fields` - :attr:`~ModelAdmin.readonly_fields` - :attr:`~InlineModelAdmin.raw_id_fields` diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index 0fa8b8e361..224c2427b0 100644 --- a/docs/ref/models/querysets.txt +++ b/docs/ref/models/querysets.txt @@ -1586,32 +1586,32 @@ The most efficient method of finding whether a model with a unique field (e.g. ``primary_key``) is a member of a :class:`.QuerySet` is:: entry = Entry.objects.get(pk=123) - if some_query_set.filter(pk=entry.pk).exists(): + if some_queryset.filter(pk=entry.pk).exists(): print("Entry contained in queryset") Which will be faster than the following which requires evaluating and iterating through the entire queryset:: - if entry in some_query_set: + if entry in some_queryset: print("Entry contained in QuerySet") And to find whether a queryset contains any items:: - if some_query_set.exists(): - print("There is at least one object in some_query_set") + if some_queryset.exists(): + print("There is at least one object in some_queryset") Which will be faster than:: - if some_query_set: - print("There is at least one object in some_query_set") + if some_queryset: + print("There is at least one object in some_queryset") ... but not by a large degree (hence needing a large queryset for efficiency gains). -Additionally, if a ``some_query_set`` has not yet been evaluated, but you know -that it will be at some point, then using ``some_query_set.exists()`` will do +Additionally, if a ``some_queryset`` has not yet been evaluated, but you know +that it will be at some point, then using ``some_queryset.exists()`` will do more overall work (one query for the existence check plus an extra one to later -retrieve the results) than simply using ``bool(some_query_set)``, which +retrieve the results) than simply using ``bool(some_queryset)``, which retrieves the results and then checks if any were returned. update diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt index 81b1e48d25..c8012ab7c2 100644 --- a/docs/releases/1.6.txt +++ b/docs/releases/1.6.txt @@ -289,3 +289,9 @@ on a widget, you should now define this method on the form field itself. ``Model._meta.module_name`` was renamed to ``model_name``. Despite being a private API, it will go through a regular deprecation path. + +``get_query_set`` and similar methods renamed to ``get_queryset`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Methods that return a ``QuerySet`` such as ``Manager.get_query_set`` or +``ModelAdmin.queryset`` have been renamed to ``get_queryset``. diff --git a/docs/topics/db/managers.txt b/docs/topics/db/managers.txt index a14616a17c..a8c0d17076 100644 --- a/docs/topics/db/managers.txt +++ b/docs/topics/db/managers.txt @@ -108,7 +108,7 @@ example, using this model:: ...the statement ``Book.objects.all()`` will return all books in the database. You can override a ``Manager``\'s base ``QuerySet`` by overriding the -``Manager.get_query_set()`` method. ``get_query_set()`` should return a +``Manager.get_queryset()`` method. ``get_queryset()`` should return a ``QuerySet`` with the properties you require. For example, the following model has *two* ``Manager``\s -- one that returns @@ -116,8 +116,8 @@ all objects, and one that returns only the books by Roald Dahl:: # First, define the Manager subclass. class DahlBookManager(models.Manager): - def get_query_set(self): - return super(DahlBookManager, self).get_query_set().filter(author='Roald Dahl') + def get_queryset(self): + return super(DahlBookManager, self).get_queryset().filter(author='Roald Dahl') # Then hook it into the Book model explicitly. class Book(models.Model): @@ -131,7 +131,7 @@ With this sample model, ``Book.objects.all()`` will return all books in the database, but ``Book.dahl_objects.all()`` will only return the ones written by Roald Dahl. -Of course, because ``get_query_set()`` returns a ``QuerySet`` object, you can +Of course, because ``get_queryset()`` returns a ``QuerySet`` object, you can use ``filter()``, ``exclude()`` and all the other ``QuerySet`` methods on it. So these statements are all legal:: @@ -147,12 +147,12 @@ models. For example:: class MaleManager(models.Manager): - def get_query_set(self): - return super(MaleManager, self).get_query_set().filter(sex='M') + def get_queryset(self): + return super(MaleManager, self).get_queryset().filter(sex='M') class FemaleManager(models.Manager): - def get_query_set(self): - return super(FemaleManager, self).get_query_set().filter(sex='F') + def get_queryset(self): + return super(FemaleManager, self).get_queryset().filter(sex='F') class Person(models.Model): first_name = models.CharField(max_length=50) @@ -172,9 +172,12 @@ the "default" ``Manager``, and several parts of Django (including :djadmin:`dumpdata`) will use that ``Manager`` exclusively for that model. As a result, it's a good idea to be careful in your choice of default manager in order to avoid a situation where overriding -``get_query_set()`` results in an inability to retrieve objects you'd like to +``get_queryset()`` results in an inability to retrieve objects you'd like to work with. +.. versionchanged:: 1.6 + The ``get_queryset`` method was previously named ``get_query_set``. + .. _managers-for-related-objects: Using managers for related object access @@ -379,9 +382,9 @@ to from some other model. In those situations, Django has to be able to see all the objects for the model it is fetching, so that *anything* which is referred to can be retrieved. -If you override the ``get_query_set()`` method and filter out any rows, Django +If you override the ``get_queryset()`` method and filter out any rows, Django will return incorrect results. Don't do that. A manager that filters results -in ``get_query_set()`` is not appropriate for use as an automatic manager. +in ``get_queryset()`` is not appropriate for use as an automatic manager. Set ``use_for_related_fields`` when you define the class ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/topics/db/multi-db.txt b/docs/topics/db/multi-db.txt index 8150e498de..ae23c3d9f3 100644 --- a/docs/topics/db/multi-db.txt +++ b/docs/topics/db/multi-db.txt @@ -506,19 +506,19 @@ solution is to use ``db_manager()``, like this:: ``db_manager()`` returns a copy of the manager bound to the database you specify. -Using ``get_query_set()`` with multiple databases +Using ``get_queryset()`` with multiple databases ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you're overriding ``get_query_set()`` on your manager, be sure to +If you're overriding ``get_queryset()`` on your manager, be sure to either call the method on the parent (using ``super()``) or do the appropriate handling of the ``_db`` attribute on the manager (a string containing the name of the database to use). For example, if you want to return a custom ``QuerySet`` class from -the ``get_query_set`` method, you could do this:: +the ``get_queryset`` method, you could do this:: class MyManager(models.Manager): - def get_query_set(self): + def get_queryset(self): qs = CustomQuerySet(self.model) if self._db is not None: qs = qs.using(self._db) @@ -548,9 +548,9 @@ multiple-database support:: # Tell Django to delete objects from the 'other' database obj.delete(using=self.using) - def queryset(self, request): + def get_queryset(self, request): # Tell Django to look for objects on the 'other' database. - return super(MultiDBModelAdmin, self).queryset(request).using(self.using) + return super(MultiDBModelAdmin, self).get_queryset(request).using(self.using) def formfield_for_foreignkey(self, db_field, request=None, **kwargs): # Tell Django to populate ForeignKey widgets using a query @@ -573,9 +573,9 @@ Inlines can be handled in a similar fashion. They require three customized metho class MultiDBTabularInline(admin.TabularInline): using = 'other' - def queryset(self, request): + def get_queryset(self, request): # Tell Django to look for inline objects on the 'other' database. - return super(MultiDBTabularInline, self).queryset(request).using(self.using) + return super(MultiDBTabularInline, self).get_queryset(request).using(self.using) def formfield_for_foreignkey(self, db_field, request=None, **kwargs): # Tell Django to populate ForeignKey widgets using a query diff --git a/tests/admin_changelist/admin.py b/tests/admin_changelist/admin.py index 5751d04bce..8387ba77a1 100644 --- a/tests/admin_changelist/admin.py +++ b/tests/admin_changelist/admin.py @@ -34,8 +34,8 @@ class ChildAdmin(admin.ModelAdmin): list_per_page = 10 list_filter = ['parent', 'age'] - def queryset(self, request): - return super(ChildAdmin, self).queryset(request).select_related("parent__name") + def get_queryset(self, request): + return super(ChildAdmin, self).get_queryset(request).select_related("parent__name") class CustomPaginationAdmin(ChildAdmin): @@ -46,8 +46,8 @@ class FilteredChildAdmin(admin.ModelAdmin): list_display = ['name', 'parent'] list_per_page = 10 - def queryset(self, request): - return super(FilteredChildAdmin, self).queryset(request).filter( + def get_queryset(self, request): + return super(FilteredChildAdmin, self).get_queryset(request).filter( name__contains='filtered') diff --git a/tests/admin_changelist/models.py b/tests/admin_changelist/models.py index 4ba2f9c503..786b4385aa 100644 --- a/tests/admin_changelist/models.py +++ b/tests/admin_changelist/models.py @@ -74,8 +74,8 @@ class UnorderedObject(models.Model): class OrderedObjectManager(models.Manager): - def get_query_set(self): - return super(OrderedObjectManager, self).get_query_set().order_by('number') + def get_queryset(self): + return super(OrderedObjectManager, self).get_queryset().order_by('number') class OrderedObject(models.Model): """ diff --git a/tests/admin_changelist/tests.py b/tests/admin_changelist/tests.py index bb39f22411..05cdcdb73d 100644 --- a/tests/admin_changelist/tests.py +++ b/tests/admin_changelist/tests.py @@ -39,15 +39,15 @@ class ChangeListTests(TestCase): def test_select_related_preserved(self): """ - Regression test for #10348: ChangeList.get_query_set() shouldn't - overwrite a custom select_related provided by ModelAdmin.queryset(). + Regression test for #10348: ChangeList.get_queryset() shouldn't + overwrite a custom select_related provided by ModelAdmin.get_queryset(). """ m = ChildAdmin(Child, admin.site) request = self.factory.get('/child/') cl = ChangeList(request, Child, m.list_display, m.list_display_links, m.list_filter, m.date_hierarchy, m.search_fields, m.list_select_related, m.list_per_page, m.list_max_show_all, m.list_editable, m) - self.assertEqual(cl.query_set.query.select_related, {'parent': {'name': {}}}) + self.assertEqual(cl.queryset.query.select_related, {'parent': {'name': {}}}) def test_result_list_empty_changelist_value(self): """ @@ -277,7 +277,7 @@ class ChangeListTests(TestCase): m.list_max_show_all, m.list_editable, m) # Make sure distinct() was called - self.assertEqual(cl.query_set.count(), 1) + self.assertEqual(cl.queryset.count(), 1) def test_distinct_for_non_unique_related_object_in_search_fields(self): """ @@ -297,7 +297,7 @@ class ChangeListTests(TestCase): m.list_max_show_all, m.list_editable, m) # Make sure distinct() was called - self.assertEqual(cl.query_set.count(), 1) + self.assertEqual(cl.queryset.count(), 1) def test_pagination(self): """ @@ -317,7 +317,7 @@ class ChangeListTests(TestCase): m.list_filter, m.date_hierarchy, m.search_fields, m.list_select_related, m.list_per_page, m.list_max_show_all, m.list_editable, m) - self.assertEqual(cl.query_set.count(), 60) + self.assertEqual(cl.queryset.count(), 60) self.assertEqual(cl.paginator.count, 60) self.assertEqual(list(cl.paginator.page_range), [1, 2, 3, 4, 5, 6]) @@ -327,7 +327,7 @@ class ChangeListTests(TestCase): m.list_filter, m.date_hierarchy, m.search_fields, m.list_select_related, m.list_per_page, m.list_max_show_all, m.list_editable, m) - self.assertEqual(cl.query_set.count(), 30) + self.assertEqual(cl.queryset.count(), 30) self.assertEqual(cl.paginator.count, 30) self.assertEqual(list(cl.paginator.page_range), [1, 2, 3]) diff --git a/tests/admin_filters/tests.py b/tests/admin_filters/tests.py index 11f792e07a..f05e8e2011 100644 --- a/tests/admin_filters/tests.py +++ b/tests/admin_filters/tests.py @@ -61,7 +61,7 @@ class DecadeListFilterWithFailingQueryset(DecadeListFilterWithTitleAndParameter) class DecadeListFilterWithQuerysetBasedLookups(DecadeListFilterWithTitleAndParameter): def lookups(self, request, model_admin): - qs = model_admin.queryset(request) + qs = model_admin.get_queryset(request) if qs.filter(year__gte=1980, year__lte=1989).exists(): yield ('the 80s', "the 1980's") if qs.filter(year__gte=1990, year__lte=1999).exists(): @@ -86,7 +86,7 @@ class DepartmentListFilterLookupWithNonStringValue(SimpleListFilter): return sorted(set([ (employee.department.id, # Intentionally not a string (Refs #19318) employee.department.code) - for employee in model_admin.queryset(request).all() + for employee in model_admin.get_queryset(request).all() ])) def queryset(self, request, queryset): @@ -183,7 +183,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.django_book, self.djangonaut_book]) # Make sure the correct choice is selected @@ -200,7 +200,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) if (self.today.year, self.today.month) == (self.one_week_ago.year, self.one_week_ago.month): # In case one week ago is in the same month. self.assertEqual(list(queryset), [self.gipsy_book, self.django_book, self.djangonaut_book]) @@ -221,7 +221,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) if self.today.year == self.one_week_ago.year: # In case one week ago is in the same year. self.assertEqual(list(queryset), [self.gipsy_book, self.django_book, self.djangonaut_book]) @@ -242,7 +242,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.gipsy_book, self.django_book, self.djangonaut_book]) # Make sure the correct choice is selected @@ -266,7 +266,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.django_book]) # Make sure the last choice is None and is selected @@ -293,7 +293,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.gipsy_book]) # Make sure the last choice is None and is selected @@ -321,7 +321,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.django_book, self.bio_book, self.djangonaut_book]) # Make sure the last choice is None and is selected @@ -349,7 +349,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, User, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.lisa]) # Make sure the last choice is None and is selected @@ -374,7 +374,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, User, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.alfred]) # Make sure the last choice is None and is selected @@ -410,7 +410,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.bio_book]) # Make sure the correct choice is selected @@ -424,7 +424,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.gipsy_book, self.djangonaut_book]) # Make sure the correct choice is selected @@ -438,7 +438,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.django_book]) # Make sure the correct choice is selected @@ -457,7 +457,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), list(Book.objects.all().order_by('-id'))) # Make sure the correct choice is selected @@ -474,7 +474,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), []) # Make sure the correct choice is selected @@ -491,7 +491,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.bio_book]) # Make sure the correct choice is selected @@ -508,7 +508,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.gipsy_book, self.djangonaut_book]) # Make sure the correct choice is selected @@ -525,7 +525,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.djangonaut_book]) # Make sure the correct choices are selected @@ -615,7 +615,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.bio_book]) filterspec = changelist.get_filters(request)[0][-1] @@ -637,7 +637,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.bio_book]) # Make sure the correct choice is selected @@ -654,7 +654,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.bio_book]) # Make sure the correct choice is selected @@ -676,7 +676,7 @@ class ListFiltersTests(TestCase): request = self.request_factory.get('/', {'department': self.john.pk}) changelist = self.get_changelist(request, Employee, modeladmin) - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.john]) @@ -698,7 +698,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Employee, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.jack, self.john]) filterspec = changelist.get_filters(request)[0][-1] @@ -723,7 +723,7 @@ class ListFiltersTests(TestCase): changelist = self.get_changelist(request, Employee, modeladmin) # Make sure the correct queryset is returned - queryset = changelist.get_query_set(request) + queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.john]) filterspec = changelist.get_filters(request)[0][-1] diff --git a/tests/admin_ordering/tests.py b/tests/admin_ordering/tests.py index 10faa9533f..6655ad37ad 100644 --- a/tests/admin_ordering/tests.py +++ b/tests/admin_ordering/tests.py @@ -22,8 +22,8 @@ request.user = MockSuperUser() class TestAdminOrdering(TestCase): """ - Let's make sure that ModelAdmin.queryset uses the ordering we define in - ModelAdmin rather that ordering defined in the model's inner Meta + Let's make sure that ModelAdmin.get_queryset uses the ordering we define + in ModelAdmin rather that ordering defined in the model's inner Meta class. """ @@ -42,7 +42,7 @@ class TestAdminOrdering(TestCase): class. """ ma = ModelAdmin(Band, None) - names = [b.name for b in ma.queryset(request)] + names = [b.name for b in ma.get_queryset(request)] self.assertEqual(['Aerosmith', 'Radiohead', 'Van Halen'], names) def test_specified_ordering(self): @@ -53,7 +53,7 @@ class TestAdminOrdering(TestCase): class BandAdmin(ModelAdmin): ordering = ('rank',) # default ordering is ('name',) ma = BandAdmin(Band, None) - names = [b.name for b in ma.queryset(request)] + names = [b.name for b in ma.get_queryset(request)] self.assertEqual(['Radiohead', 'Van Halen', 'Aerosmith'], names) def test_dynamic_ordering(self): @@ -65,17 +65,17 @@ class TestAdminOrdering(TestCase): request = self.request_factory.get('/') request.user = super_user ma = DynOrderingBandAdmin(Band, None) - names = [b.name for b in ma.queryset(request)] + names = [b.name for b in ma.get_queryset(request)] self.assertEqual(['Radiohead', 'Van Halen', 'Aerosmith'], names) request.user = other_user - names = [b.name for b in ma.queryset(request)] + names = [b.name for b in ma.get_queryset(request)] self.assertEqual(['Aerosmith', 'Radiohead', 'Van Halen'], names) class TestInlineModelAdminOrdering(TestCase): """ - Let's make sure that InlineModelAdmin.queryset uses the ordering we define - in InlineModelAdmin. + Let's make sure that InlineModelAdmin.get_queryset uses the ordering we + define in InlineModelAdmin. """ def setUp(self): @@ -95,7 +95,7 @@ class TestInlineModelAdminOrdering(TestCase): class. """ inline = SongInlineDefaultOrdering(self.b, None) - names = [s.name for s in inline.queryset(request)] + names = [s.name for s in inline.get_queryset(request)] self.assertEqual(['Dude (Looks Like a Lady)', 'Jaded', 'Pink'], names) def test_specified_ordering(self): @@ -103,7 +103,7 @@ class TestInlineModelAdminOrdering(TestCase): Let's check with ordering set to something different than the default. """ inline = SongInlineNewOrdering(self.b, None) - names = [s.name for s in inline.queryset(request)] + names = [s.name for s in inline.get_queryset(request)] self.assertEqual(['Jaded', 'Pink', 'Dude (Looks Like a Lady)'], names) diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py index d4348968e0..cc7585cd2d 100644 --- a/tests/admin_views/admin.py +++ b/tests/admin_views/admin.py @@ -177,10 +177,10 @@ class PersonAdmin(admin.ModelAdmin): return super(PersonAdmin, self).get_changelist_formset(request, formset=BasePersonModelFormSet, **kwargs) - def queryset(self, request): + def get_queryset(self, request): # Order by a field that isn't in list display, to be able to test # whether ordering is preserved. - return super(PersonAdmin, self).queryset(request).order_by('age') + return super(PersonAdmin, self).get_queryset(request).order_by('age') class FooAccount(Account): @@ -283,8 +283,8 @@ class ParentAdmin(admin.ModelAdmin): class EmptyModelAdmin(admin.ModelAdmin): - def queryset(self, request): - return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1) + def get_queryset(self, request): + return super(EmptyModelAdmin, self).get_queryset(request).filter(pk__gt=1) class OldSubscriberAdmin(admin.ModelAdmin): @@ -427,8 +427,8 @@ class PostAdmin(admin.ModelAdmin): class CustomChangeList(ChangeList): - def get_query_set(self, request): - return self.root_query_set.filter(pk=9999) # Does not exist + def get_queryset(self, request): + return self.root_queryset.filter(pk=9999) # Does not exist class GadgetAdmin(admin.ModelAdmin): @@ -452,52 +452,52 @@ class FoodDeliveryAdmin(admin.ModelAdmin): class CoverLetterAdmin(admin.ModelAdmin): """ - A ModelAdmin with a custom queryset() method that uses defer(), to test + A ModelAdmin with a custom get_queryset() method that uses defer(), to test verbose_name display in messages shown after adding/editing CoverLetter instances. Note that the CoverLetter model defines a __unicode__ method. For testing fix for ticket #14529. """ - def queryset(self, request): - return super(CoverLetterAdmin, self).queryset(request).defer('date_written') + def get_queryset(self, request): + return super(CoverLetterAdmin, self).get_queryset(request).defer('date_written') class PaperAdmin(admin.ModelAdmin): """ - A ModelAdmin with a custom queryset() method that uses only(), to test + A ModelAdmin with a custom get_queryset() method that uses only(), to test verbose_name display in messages shown after adding/editing Paper instances. For testing fix for ticket #14529. """ - def queryset(self, request): - return super(PaperAdmin, self).queryset(request).only('title') + def get_queryset(self, request): + return super(PaperAdmin, self).get_queryset(request).only('title') class ShortMessageAdmin(admin.ModelAdmin): """ - A ModelAdmin with a custom queryset() method that uses defer(), to test + A ModelAdmin with a custom get_queryset() method that uses defer(), to test verbose_name display in messages shown after adding/editing ShortMessage instances. For testing fix for ticket #14529. """ - def queryset(self, request): - return super(ShortMessageAdmin, self).queryset(request).defer('timestamp') + def get_queryset(self, request): + return super(ShortMessageAdmin, self).get_queryset(request).defer('timestamp') class TelegramAdmin(admin.ModelAdmin): """ - A ModelAdmin with a custom queryset() method that uses only(), to test + A ModelAdmin with a custom get_queryset() method that uses only(), to test verbose_name display in messages shown after adding/editing Telegram instances. Note that the Telegram model defines a __unicode__ method. For testing fix for ticket #14529. """ - def queryset(self, request): - return super(TelegramAdmin, self).queryset(request).only('title') + def get_queryset(self, request): + return super(TelegramAdmin, self).get_queryset(request).only('title') class StoryForm(forms.ModelForm): diff --git a/tests/admin_views/customadmin.py b/tests/admin_views/customadmin.py index d69d690af0..c204b81edd 100644 --- a/tests/admin_views/customadmin.py +++ b/tests/admin_views/customadmin.py @@ -35,8 +35,8 @@ class Admin2(admin.AdminSite): class UserLimitedAdmin(UserAdmin): # used for testing password change on a user not in queryset - def queryset(self, request): - qs = super(UserLimitedAdmin, self).queryset(request) + def get_queryset(self, request): + qs = super(UserLimitedAdmin, self).get_queryset(request) return qs.filter(is_superuser=False) diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index ff2eb95745..53dc74fa88 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -291,7 +291,7 @@ class AdminViewBasicTest(TestCase): """ If no ordering is defined in `ModelAdmin.ordering` or in the query string, then the underlying order of the queryset should not be - changed, even if it is defined in `Modeladmin.queryset()`. + changed, even if it is defined in `Modeladmin.get_queryset()`. Refs #11868, #7309. """ p1 = Person.objects.create(name="Amy", gender=1, alive=True, age=80) @@ -440,7 +440,7 @@ class AdminViewBasicTest(TestCase): self.urlbit, query_string)) self.assertEqual(filtered_response.status_code, 200) # ensure changelist contains only valid objects - for obj in filtered_response.context['cl'].query_set.all(): + for obj in filtered_response.context['cl'].queryset.all(): self.assertTrue(params['test'](obj, value)) def testIncorrectLookupParameters(self): @@ -2583,7 +2583,7 @@ class AdminCustomQuerysetTest(TestCase): self.assertEqual(response.status_code, 404) def test_add_model_modeladmin_defer_qs(self): - # Test for #14529. defer() is used in ModelAdmin.queryset() + # Test for #14529. defer() is used in ModelAdmin.get_queryset() # model has __unicode__ method self.assertEqual(CoverLetter.objects.count(), 0) @@ -2622,7 +2622,7 @@ class AdminCustomQuerysetTest(TestCase): ) def test_add_model_modeladmin_only_qs(self): - # Test for #14529. only() is used in ModelAdmin.queryset() + # Test for #14529. only() is used in ModelAdmin.get_queryset() # model has __unicode__ method self.assertEqual(Telegram.objects.count(), 0) @@ -2661,7 +2661,7 @@ class AdminCustomQuerysetTest(TestCase): ) def test_edit_model_modeladmin_defer_qs(self): - # Test for #14529. defer() is used in ModelAdmin.queryset() + # Test for #14529. defer() is used in ModelAdmin.get_queryset() # model has __unicode__ method cl = CoverLetter.objects.create(author="John Doe") @@ -2708,7 +2708,7 @@ class AdminCustomQuerysetTest(TestCase): ) def test_edit_model_modeladmin_only_qs(self): - # Test for #14529. only() is used in ModelAdmin.queryset() + # Test for #14529. only() is used in ModelAdmin.get_queryset() # model has __unicode__ method t = Telegram.objects.create(title="Frist Telegram") diff --git a/tests/admin_widgets/models.py b/tests/admin_widgets/models.py index 2977b86f3e..ae19d58cc4 100644 --- a/tests/admin_widgets/models.py +++ b/tests/admin_widgets/models.py @@ -37,8 +37,8 @@ class Album(models.Model): return self.name class HiddenInventoryManager(models.Manager): - def get_query_set(self): - return super(HiddenInventoryManager, self).get_query_set().filter(hidden=False) + def get_queryset(self): + return super(HiddenInventoryManager, self).get_queryset().filter(hidden=False) @python_2_unicode_compatible class Inventory(models.Model): diff --git a/tests/custom_managers/models.py b/tests/custom_managers/models.py index de7c1772ed..2f5e62fc7a 100644 --- a/tests/custom_managers/models.py +++ b/tests/custom_managers/models.py @@ -30,11 +30,11 @@ class Person(models.Model): def __str__(self): return "%s %s" % (self.first_name, self.last_name) -# An example of a custom manager that sets get_query_set(). +# An example of a custom manager that sets get_queryset(). class PublishedBookManager(models.Manager): - def get_query_set(self): - return super(PublishedBookManager, self).get_query_set().filter(is_published=True) + def get_queryset(self): + return super(PublishedBookManager, self).get_queryset().filter(is_published=True) @python_2_unicode_compatible class Book(models.Model): @@ -50,8 +50,8 @@ class Book(models.Model): # An example of providing multiple custom managers. class FastCarManager(models.Manager): - def get_query_set(self): - return super(FastCarManager, self).get_query_set().filter(top_speed__gt=150) + def get_queryset(self): + return super(FastCarManager, self).get_queryset().filter(top_speed__gt=150) @python_2_unicode_compatible class Car(models.Model): diff --git a/tests/custom_managers_regress/models.py b/tests/custom_managers_regress/models.py index 71073f0fe7..95cf6e8ca1 100644 --- a/tests/custom_managers_regress/models.py +++ b/tests/custom_managers_regress/models.py @@ -10,8 +10,8 @@ class RestrictedManager(models.Manager): """ A manager that filters out non-public instances. """ - def get_query_set(self): - return super(RestrictedManager, self).get_query_set().filter(is_public=True) + def get_queryset(self): + return super(RestrictedManager, self).get_queryset().filter(is_public=True) @python_2_unicode_compatible class RelatedModel(models.Model): diff --git a/tests/deprecation/__init__.py b/tests/deprecation/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/deprecation/models.py b/tests/deprecation/models.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/deprecation/tests.py b/tests/deprecation/tests.py new file mode 100644 index 0000000000..df752b3149 --- /dev/null +++ b/tests/deprecation/tests.py @@ -0,0 +1,158 @@ +from __future__ import unicode_literals +import warnings + +from django.test.testcases import SimpleTestCase +from django.utils import six +from django.utils.deprecation import RenameMethodsBase + + +class RenameManagerMethods(RenameMethodsBase): + renamed_methods = ( + ('old', 'new', PendingDeprecationWarning), + ) + + +class RenameMethodsTests(SimpleTestCase): + """ + Tests the `RenameMethodsBase` type introduced to rename `get_query_set` + to `get_queryset` across the code base following #15363. + """ + + def test_class_definition_warnings(self): + """ + Ensure a warning is raised upon class definition to suggest renaming + the faulty method. + """ + with warnings.catch_warnings(record=True) as recorded: + warnings.simplefilter('always') + class Manager(six.with_metaclass(RenameManagerMethods)): + def old(self): + pass + self.assertEqual(len(recorded), 1) + msg = str(recorded[0].message) + self.assertEqual(msg, + '`Manager.old` method should be renamed `new`.') + + def test_get_new_defined(self): + """ + Ensure `old` complains and not `new` when only `new` is defined. + """ + with warnings.catch_warnings(record=True) as recorded: + warnings.simplefilter('ignore') + class Manager(six.with_metaclass(RenameManagerMethods)): + def new(self): + pass + warnings.simplefilter('always') + manager = Manager() + manager.new() + self.assertEqual(len(recorded), 0) + manager.old() + self.assertEqual(len(recorded), 1) + msg = str(recorded.pop().message) + self.assertEqual(msg, + '`Manager.old` is deprecated, use `new` instead.') + + def test_get_old_defined(self): + """ + Ensure `old` complains when only `old` is defined. + """ + with warnings.catch_warnings(record=True) as recorded: + warnings.simplefilter('ignore') + class Manager(six.with_metaclass(RenameManagerMethods)): + def old(self): + pass + warnings.simplefilter('always') + manager = Manager() + manager.new() + self.assertEqual(len(recorded), 0) + manager.old() + self.assertEqual(len(recorded), 1) + msg = str(recorded.pop().message) + self.assertEqual(msg, + '`Manager.old` is deprecated, use `new` instead.') + + def test_deprecated_subclass_renamed(self): + """ + Ensure the correct warnings are raised when a class that didn't rename + `old` subclass one that did. + """ + with warnings.catch_warnings(record=True) as recorded: + warnings.simplefilter('ignore') + class Renamed(six.with_metaclass(RenameManagerMethods)): + def new(self): + pass + class Deprecated(Renamed): + def old(self): + super(Deprecated, self).old() + warnings.simplefilter('always') + deprecated = Deprecated() + deprecated.new() + self.assertEqual(len(recorded), 1) + msg = str(recorded.pop().message) + self.assertEqual(msg, + '`Renamed.old` is deprecated, use `new` instead.') + recorded[:] = [] + deprecated.old() + self.assertEqual(len(recorded), 2) + msgs = [str(warning.message) for warning in recorded] + self.assertEqual(msgs, [ + '`Deprecated.old` is deprecated, use `new` instead.', + '`Renamed.old` is deprecated, use `new` instead.', + ]) + + def test_renamed_subclass_deprecated(self): + """ + Ensure the correct warnings are raised when a class that renamed + `old` subclass one that didn't. + """ + with warnings.catch_warnings(record=True) as recorded: + warnings.simplefilter('ignore') + class Deprecated(six.with_metaclass(RenameManagerMethods)): + def old(self): + pass + class Renamed(Deprecated): + def new(self): + super(Renamed, self).new() + warnings.simplefilter('always') + renamed = Renamed() + renamed.new() + self.assertEqual(len(recorded), 0) + renamed.old() + self.assertEqual(len(recorded), 1) + msg = str(recorded.pop().message) + self.assertEqual(msg, + '`Renamed.old` is deprecated, use `new` instead.') + + def test_deprecated_subclass_renamed_and_mixins(self): + """ + Ensure the correct warnings are raised when a subclass inherit from a + class that renamed `old` and mixins that may or may not have renamed + `new`. + """ + with warnings.catch_warnings(record=True) as recorded: + warnings.simplefilter('ignore') + class Renamed(six.with_metaclass(RenameManagerMethods)): + def new(self): + pass + class RenamedMixin(object): + def new(self): + super(RenamedMixin, self).new() + class DeprecatedMixin(object): + def old(self): + super(DeprecatedMixin, self).old() + class Deprecated(DeprecatedMixin, RenamedMixin, Renamed): + pass + warnings.simplefilter('always') + deprecated = Deprecated() + deprecated.new() + self.assertEqual(len(recorded), 1) + msg = str(recorded.pop().message) + self.assertEqual(msg, + '`RenamedMixin.old` is deprecated, use `new` instead.') + deprecated.old() + self.assertEqual(len(recorded), 2) + msgs = [str(warning.message) for warning in recorded] + self.assertEqual(msgs, [ + '`DeprecatedMixin.old` is deprecated, use `new` instead.', + '`RenamedMixin.old` is deprecated, use `new` instead.', + ]) diff --git a/tests/fixtures/models.py b/tests/fixtures/models.py index 8bd3501926..976716fdc9 100644 --- a/tests/fixtures/models.py +++ b/tests/fixtures/models.py @@ -78,8 +78,8 @@ class Person(models.Model): return (self.name,) class SpyManager(PersonManager): - def get_query_set(self): - return super(SpyManager, self).get_query_set().filter(cover_blown=False) + def get_queryset(self): + return super(SpyManager, self).get_queryset().filter(cover_blown=False) class Spy(Person): objects = SpyManager() diff --git a/tests/generic_relations/models.py b/tests/generic_relations/models.py index 18d7623971..34dc8d3a7d 100644 --- a/tests/generic_relations/models.py +++ b/tests/generic_relations/models.py @@ -88,8 +88,8 @@ class Mineral(models.Model): return self.name class GeckoManager(models.Manager): - def get_query_set(self): - return super(GeckoManager, self).get_query_set().filter(has_tail=True) + def get_queryset(self): + return super(GeckoManager, self).get_queryset().filter(has_tail=True) class Gecko(models.Model): has_tail = models.BooleanField() diff --git a/tests/get_object_or_404/models.py b/tests/get_object_or_404/models.py index bda060569e..bb9aa60383 100644 --- a/tests/get_object_or_404/models.py +++ b/tests/get_object_or_404/models.py @@ -22,8 +22,8 @@ class Author(models.Model): return self.name class ArticleManager(models.Manager): - def get_query_set(self): - return super(ArticleManager, self).get_query_set().filter(authors__name__icontains='sir') + def get_queryset(self): + return super(ArticleManager, self).get_queryset().filter(authors__name__icontains='sir') @python_2_unicode_compatible class Article(models.Model): diff --git a/tests/managers_regress/models.py b/tests/managers_regress/models.py index d72970d86e..d8dd22ec9a 100644 --- a/tests/managers_regress/models.py +++ b/tests/managers_regress/models.py @@ -7,18 +7,18 @@ from django.utils.encoding import python_2_unicode_compatible class OnlyFred(models.Manager): - def get_query_set(self): - return super(OnlyFred, self).get_query_set().filter(name='fred') + def get_queryset(self): + return super(OnlyFred, self).get_queryset().filter(name='fred') class OnlyBarney(models.Manager): - def get_query_set(self): - return super(OnlyBarney, self).get_query_set().filter(name='barney') + def get_queryset(self): + return super(OnlyBarney, self).get_queryset().filter(name='barney') class Value42(models.Manager): - def get_query_set(self): - return super(Value42, self).get_query_set().filter(value=42) + def get_queryset(self): + return super(Value42, self).get_queryset().filter(value=42) class AbstractBase1(models.Model): diff --git a/tests/modeladmin/tests.py b/tests/modeladmin/tests.py index b0a181218b..e5450ab8ff 100644 --- a/tests/modeladmin/tests.py +++ b/tests/modeladmin/tests.py @@ -69,7 +69,7 @@ class ModelAdminTests(TestCase): # If we specify the fields argument, fieldsets_add and fielsets_change should # just stick the fields into a formsets structure and return it. class BandAdmin(ModelAdmin): - fields = ['name'] + fields = ['name'] ma = BandAdmin(Band, self.site) @@ -1074,7 +1074,7 @@ class ValidationTests(unittest.TestCase): return 'awesomeness' def get_choices(self, request): return (('bit', 'A bit awesome'), ('very', 'Very awesome'), ) - def get_query_set(self, cl, qs): + def get_queryset(self, cl, qs): return qs class ValidationTestModelAdmin(ModelAdmin): diff --git a/tests/prefetch_related/models.py b/tests/prefetch_related/models.py index e58997d200..81c569844f 100644 --- a/tests/prefetch_related/models.py +++ b/tests/prefetch_related/models.py @@ -87,8 +87,8 @@ class Qualification(models.Model): class TeacherManager(models.Manager): - def get_query_set(self): - return super(TeacherManager, self).get_query_set().prefetch_related('qualifications') + def get_queryset(self): + return super(TeacherManager, self).get_queryset().prefetch_related('qualifications') @python_2_unicode_compatible diff --git a/tests/proxy_models/models.py b/tests/proxy_models/models.py index 6c962aadc8..ffb36657e1 100644 --- a/tests/proxy_models/models.py +++ b/tests/proxy_models/models.py @@ -10,12 +10,12 @@ from django.utils.encoding import python_2_unicode_compatible # A couple of managers for testing managing overriding in proxy model cases. class PersonManager(models.Manager): - def get_query_set(self): - return super(PersonManager, self).get_query_set().exclude(name="fred") + def get_queryset(self): + return super(PersonManager, self).get_queryset().exclude(name="fred") class SubManager(models.Manager): - def get_query_set(self): - return super(SubManager, self).get_query_set().exclude(name="wilma") + def get_queryset(self): + return super(SubManager, self).get_queryset().exclude(name="wilma") @python_2_unicode_compatible class Person(models.Model): diff --git a/tests/queries/models.py b/tests/queries/models.py index c8598371a6..f7f643d585 100644 --- a/tests/queries/models.py +++ b/tests/queries/models.py @@ -176,8 +176,8 @@ class LoopZ(models.Model): # A model and custom default manager combination. class CustomManager(models.Manager): - def get_query_set(self): - qs = super(CustomManager, self).get_query_set() + def get_queryset(self): + qs = super(CustomManager, self).get_queryset() return qs.filter(public=True, tag__name='t1') @python_2_unicode_compatible @@ -197,8 +197,8 @@ class Detail(models.Model): data = models.CharField(max_length=10) class MemberManager(models.Manager): - def get_query_set(self): - return super(MemberManager, self).get_query_set().select_related("details") + def get_queryset(self): + return super(MemberManager, self).get_queryset().select_related("details") class Member(models.Model): name = models.CharField(max_length=10) diff --git a/tests/reverse_single_related/models.py b/tests/reverse_single_related/models.py index 898be8411b..30ba345120 100644 --- a/tests/reverse_single_related/models.py +++ b/tests/reverse_single_related/models.py @@ -2,8 +2,8 @@ from django.db import models class SourceManager(models.Manager): - def get_query_set(self): - return super(SourceManager, self).get_query_set().filter(is_public=True) + def get_queryset(self): + return super(SourceManager, self).get_queryset().filter(is_public=True) class Source(models.Model): is_public = models.BooleanField()