From 484fcd34a4819ff11ef72f3c9e1eb467a282b2f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anssi=20K=C3=A4=C3=A4ri=C3=A4inen?= Date: Sat, 9 Jun 2012 01:12:14 +0300 Subject: [PATCH] Fixed #16418 -- Made generic views work with ModelForms Generic views assumed any object's _meta will be model Options. This is not true for ModelForms for example. Took isinstance(obj, Model) in use instead. --- django/views/generic/detail.py | 7 ++++--- tests/regressiontests/generic_views/detail.py | 5 +++++ tests/regressiontests/generic_views/urls.py | 2 ++ tests/regressiontests/generic_views/views.py | 15 +++++++++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/django/views/generic/detail.py b/django/views/generic/detail.py index 8cc413aa65..a5ddb5fe3e 100644 --- a/django/views/generic/detail.py +++ b/django/views/generic/detail.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist +from django.db import models from django.http import Http404 from django.utils.translation import ugettext as _ from django.views.generic.base import TemplateResponseMixin, ContextMixin, View @@ -81,7 +82,7 @@ class SingleObjectMixin(ContextMixin): """ if self.context_object_name: return self.context_object_name - elif hasattr(obj, '_meta'): + elif isinstance(obj, models.Model): return obj._meta.object_name.lower() else: return None @@ -128,13 +129,13 @@ class SingleObjectTemplateResponseMixin(TemplateResponseMixin): # The least-specific option is the default /_detail.html; # only use this if the object in question is a model. - if hasattr(self.object, '_meta'): + if isinstance(self.object, models.Model): names.append("%s/%s%s.html" % ( self.object._meta.app_label, self.object._meta.object_name.lower(), self.template_name_suffix )) - elif hasattr(self, 'model') and hasattr(self.model, '_meta'): + elif hasattr(self, 'model') and self.model is not None and issubclass(self.model, models.Model): names.append("%s/%s%s.html" % ( self.model._meta.app_label, self.model._meta.object_name.lower(), diff --git a/tests/regressiontests/generic_views/detail.py b/tests/regressiontests/generic_views/detail.py index 0b5d8737dd..60c5f7afe9 100644 --- a/tests/regressiontests/generic_views/detail.py +++ b/tests/regressiontests/generic_views/detail.py @@ -92,3 +92,8 @@ class DetailViewTest(TestCase): def test_invalid_queryset(self): self.assertRaises(ImproperlyConfigured, self.client.get, '/detail/author/invalid/qs/') + + def test_non_model_object_with_meta(self): + res = self.client.get('/detail/nonmodel/1/') + self.assertEqual(res.status_code, 200) + self.assertEqual(res.context['object'].id, "non_model_1") diff --git a/tests/regressiontests/generic_views/urls.py b/tests/regressiontests/generic_views/urls.py index 14d4f685a6..5e15c6c9c1 100644 --- a/tests/regressiontests/generic_views/urls.py +++ b/tests/regressiontests/generic_views/urls.py @@ -53,6 +53,8 @@ urlpatterns = patterns('', views.AuthorDetail.as_view()), (r'^detail/author/invalid/qs/$', views.AuthorDetail.as_view(queryset=None)), + (r'^detail/nonmodel/1/$', + views.NonModelDetail.as_view()), # Create/UpdateView (r'^edit/artists/create/$', diff --git a/tests/regressiontests/generic_views/views.py b/tests/regressiontests/generic_views/views.py index d11d810f3d..f7fcf6f509 100644 --- a/tests/regressiontests/generic_views/views.py +++ b/tests/regressiontests/generic_views/views.py @@ -226,3 +226,18 @@ class BookSigningTodayArchive(BookSigningConfig, generic.TodayArchiveView): class BookSigningDetail(BookSigningConfig, generic.DateDetailView): context_object_name = 'book' + + +class NonModel(object): + id = "non_model_1" + + _meta = None + + +class NonModelDetail(generic.DetailView): + + template_name = 'generic_views/detail.html' + model = NonModel + + def get_object(self, queryset=None): + return NonModel()