From f8a6a4eba1b52dd634ab3e72637cd47412dcfa6e Mon Sep 17 00:00:00 2001 From: Loic Bistuer Date: Fri, 9 Aug 2013 17:31:17 +0700 Subject: [PATCH] Improved queryset handling and docs for (Single|Multiple)ObjectMixin. --- django/views/generic/detail.py | 20 +++++++++++-------- django/views/generic/list.py | 20 +++++++++++++------ .../mixins-multiple-object.txt | 8 ++++++++ .../mixins-single-object.txt | 8 ++++++++ 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/django/views/generic/detail.py b/django/views/generic/detail.py index 23000641b4..5ce8092c67 100644 --- a/django/views/generic/detail.py +++ b/django/views/generic/detail.py @@ -57,19 +57,23 @@ class SingleObjectMixin(ContextMixin): def get_queryset(self): """ - Get the queryset to look an object up against. May not be called if - `get_object` is overridden. + Return the `QuerySet` that will be used to look up the object. + + Note that this method is called by the default implementation of + `get_object` and may not be called if `get_object` is overriden. """ if self.queryset is None: if self.model: return self.model._default_manager.all() else: - raise ImproperlyConfigured("%(cls)s is missing a queryset. Define " - "%(cls)s.model, %(cls)s.queryset, or override " - "%(cls)s.get_queryset()." % { - 'cls': self.__class__.__name__ - }) - return self.queryset._clone() + raise ImproperlyConfigured( + "%(cls)s is missing a QuerySet. Define " + "%(cls)s.model, %(cls)s.queryset, or override " + "%(cls)s.get_queryset()." % { + 'cls': self.__class__.__name__ + } + ) + return self.queryset.all() def get_slug_field(self): """ diff --git a/django/views/generic/list.py b/django/views/generic/list.py index 1aff3454f4..7381fd1be9 100644 --- a/django/views/generic/list.py +++ b/django/views/generic/list.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.core.paginator import Paginator, InvalidPage from django.core.exceptions import ImproperlyConfigured +from django.db.models.query import QuerySet from django.http import Http404 from django.utils.translation import ugettext as _ from django.views.generic.base import TemplateResponseMixin, ContextMixin, View @@ -22,18 +23,25 @@ class MultipleObjectMixin(ContextMixin): def get_queryset(self): """ - Get the list of items for this view. This must be an iterable, and may - be a queryset (in which qs-specific behavior will be enabled). + Return the list of items for this view. + + The return value must be an iterable and may be an instance of + `QuerySet` in which case `QuerySet` specific behavior will be enabled. """ if self.queryset is not None: queryset = self.queryset - if hasattr(queryset, '_clone'): - queryset = queryset._clone() + if isinstance(queryset, QuerySet): + queryset = queryset.all() elif self.model is not None: queryset = self.model._default_manager.all() else: - raise ImproperlyConfigured("'%s' must define 'queryset' or 'model'" - % self.__class__.__name__) + raise ImproperlyConfigured( + "%(cls)s is missing a QuerySet. Define " + "%(cls)s.model, %(cls)s.queryset, or override " + "%(cls)s.get_queryset()." % { + 'cls': self.__class__.__name__ + } + ) return queryset def paginate_queryset(self, queryset, page_size): diff --git a/docs/ref/class-based-views/mixins-multiple-object.txt b/docs/ref/class-based-views/mixins-multiple-object.txt index b28bd11a71..67ca5429fa 100644 --- a/docs/ref/class-based-views/mixins-multiple-object.txt +++ b/docs/ref/class-based-views/mixins-multiple-object.txt @@ -63,6 +63,14 @@ MultipleObjectMixin A ``QuerySet`` that represents the objects. If provided, the value of ``queryset`` supersedes the value provided for :attr:`model`. + .. warning:: + + ``queryset`` is a class attribute with a *mutable* value so care + must be taken when using it directly. Before using it, either call + its :meth:`~django.db.models.query.QuerySet.all` method or + retrieve it with :meth:`get_queryset` which takes care of the + cloning behind the scenes. + .. attribute:: paginate_by An integer specifying how many objects should be displayed per page. If diff --git a/docs/ref/class-based-views/mixins-single-object.txt b/docs/ref/class-based-views/mixins-single-object.txt index bbe930d79e..1fce24acc5 100644 --- a/docs/ref/class-based-views/mixins-single-object.txt +++ b/docs/ref/class-based-views/mixins-single-object.txt @@ -23,6 +23,14 @@ SingleObjectMixin A ``QuerySet`` that represents the objects. If provided, the value of ``queryset`` supersedes the value provided for :attr:`model`. + .. warning:: + + ``queryset`` is a class attribute with a *mutable* value so care + must be taken when using it directly. Before using it, either call + its :meth:`~django.db.models.query.QuerySet.all` method or + retrieve it with :meth:`get_queryset` which takes care of the + cloning behind the scenes. + .. attribute:: slug_field The name of the field on the model that contains the slug. By default,