Commit 6ed6a18a authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #19432 -- Provided better error message for get_object_or_404

Thanks Kit Sunde for the report and Brian Holdefehr for the initial
patch.
parent 6cad5f21
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ for convenience's sake.
from django.template import loader, RequestContext
from django.http import HttpResponse, Http404
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
from django.db.models.base import ModelBase
from django.db.models.manager import Manager
from django.db.models.query import QuerySet
from django.core import urlresolvers
@@ -72,13 +73,20 @@ def _get_queryset(klass):
    """
    Returns a QuerySet from a Model, Manager, or QuerySet. Created to make
    get_object_or_404 and get_list_or_404 more DRY.

    Raises a ValueError if klass is not a Model, Manager, or QuerySet.
    """
    if isinstance(klass, QuerySet):
        return klass
    elif isinstance(klass, Manager):
        manager = klass
    else:
    elif isinstance(klass, ModelBase):
        manager = klass._default_manager
    else:
        klass__name = klass.__name__ if isinstance(klass, type) \
                      else klass.__class__.__name__
        raise ValueError("Object is of type '%s', but must be a Django Model, "
                         "Manager, or QuerySet" % klass__name)
    return manager.all()

def get_object_or_404(klass, *args, **kwargs):
+25 −0
Original line number Diff line number Diff line
@@ -80,3 +80,28 @@ class GetObjectOr404Tests(TestCase):
            get_list_or_404(Article.objects.all(), title__icontains="Run"),
            [article]
        )

    def test_bad_class(self):
        # Given an argument klass that is not a Model, Manager, or Queryset
        # raises a helpful ValueError message
        self.assertRaisesMessage(ValueError,
            "Object is of type 'str', but must be a Django Model, Manager, "
            "or QuerySet",
            get_object_or_404, "Article", title__icontains="Run"
        )

        class CustomClass(object):
            pass

        self.assertRaisesMessage(ValueError,
            "Object is of type 'CustomClass', but must be a Django Model, "
            "Manager, or QuerySet",
            get_object_or_404, CustomClass, title__icontains="Run"
        )

        # Works for lists too
        self.assertRaisesMessage(ValueError,
            "Object is of type 'list', but must be a Django Model, Manager, "
            "or QuerySet",
            get_list_or_404, [Article], title__icontains="Run"
        )