From cdd6617da679e19059907979b03c4ef7b15691e6 Mon Sep 17 00:00:00 2001 From: Peter Harley Date: Sat, 14 Dec 2013 23:15:35 +0000 Subject: [PATCH] Fixed #21619 -- Made SingleObjectMixin.get_object catch a more precise exception. Thanks to Keryn Knight for the report. --- django/views/generic/detail.py | 4 ++-- tests/generic_views/models.py | 12 ++++++++++++ tests/generic_views/test_detail.py | 9 ++++++++- tests/generic_views/urls.py | 3 ++- tests/generic_views/views.py | 5 +++++ 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/django/views/generic/detail.py b/django/views/generic/detail.py index 466954c03a..f25b416498 100644 --- a/django/views/generic/detail.py +++ b/django/views/generic/detail.py @@ -1,6 +1,6 @@ from __future__ import unicode_literals -from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist +from django.core.exceptions import ImproperlyConfigured from django.db import models from django.http import Http404 from django.utils.translation import ugettext as _ @@ -50,7 +50,7 @@ class SingleObjectMixin(ContextMixin): try: # Get the single item from the filtered queryset obj = queryset.get() - except ObjectDoesNotExist: + except queryset.model.DoesNotExist: raise Http404(_("No %(verbose_name)s found matching the query") % {'verbose_name': queryset.model._meta.verbose_name}) return obj diff --git a/tests/generic_views/models.py b/tests/generic_views/models.py index f5554d1a20..d27a2fa912 100644 --- a/tests/generic_views/models.py +++ b/tests/generic_views/models.py @@ -1,5 +1,7 @@ from django.core.urlresolvers import reverse from django.db import models +from django.db.models import QuerySet +from django.db.models.manager import BaseManager from django.utils.encoding import python_2_unicode_compatible @@ -31,6 +33,13 @@ class Author(models.Model): return self.name +class DoesNotExistQuerySet(QuerySet): + def get(self, *args, **kwargs): + raise Author.DoesNotExist + +DoesNotExistBookManager = BaseManager.from_queryset(DoesNotExistQuerySet) + + @python_2_unicode_compatible class Book(models.Model): name = models.CharField(max_length=300) @@ -39,6 +48,9 @@ class Book(models.Model): authors = models.ManyToManyField(Author) pubdate = models.DateField() + objects = models.Manager() + does_not_exist = DoesNotExistBookManager() + class Meta: ordering = ['-pubdate'] diff --git a/tests/generic_views/test_detail.py b/tests/generic_views/test_detail.py index 8a487a7c3d..7fdbd76ce0 100644 --- a/tests/generic_views/test_detail.py +++ b/tests/generic_views/test_detail.py @@ -1,6 +1,6 @@ from __future__ import unicode_literals -from django.core.exceptions import ImproperlyConfigured +from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist from django.test import TestCase from django.views.generic.base import View @@ -25,6 +25,13 @@ class DetailViewTest(TestCase): self.assertEqual(res.context['author'], Author.objects.get(pk=1)) self.assertTemplateUsed(res, 'generic_views/author_detail.html') + def test_detail_missing_object(self): + res = self.client.get('/detail/author/500/') + self.assertEqual(res.status_code, 404) + + def test_detail_object_does_not_exist(self): + self.assertRaises(ObjectDoesNotExist, self.client.get, '/detail/doesnotexist/1/') + def test_detail_by_custom_pk(self): res = self.client.get('/detail/author/bycustompk/1/') self.assertEqual(res.status_code, 200) diff --git a/tests/generic_views/urls.py b/tests/generic_views/urls.py index 20cb6a8e48..8b2560b0f9 100644 --- a/tests/generic_views/urls.py +++ b/tests/generic_views/urls.py @@ -55,7 +55,8 @@ urlpatterns = patterns('', views.AuthorDetail.as_view(queryset=None)), (r'^detail/nonmodel/1/$', views.NonModelDetail.as_view()), - + (r'^detail/doesnotexist/(?P\d+)/$', + views.ObjectDoesNotExistDetail.as_view()), # FormView (r'^contact/$', views.ContactView.as_view()), diff --git a/tests/generic_views/views.py b/tests/generic_views/views.py index 00e74d4708..fc91799f56 100644 --- a/tests/generic_views/views.py +++ b/tests/generic_views/views.py @@ -300,3 +300,8 @@ class NonModelDetail(generic.DetailView): def get_object(self, queryset=None): return NonModel() + + +class ObjectDoesNotExistDetail(generic.DetailView): + def get_queryset(self): + return Book.does_not_exist.all()