diff --git a/django/views/generic/edit.py b/django/views/generic/edit.py index 33a312709d..ff87f7bd14 100644 --- a/django/views/generic/edit.py +++ b/django/views/generic/edit.py @@ -75,7 +75,17 @@ class ModelFormMixin(FormMixin, SingleObjectMixin): if self.form_class: return self.form_class else: - model = self.get_queryset().model + if self.model is not None: + # If a model has been explicitly provided, use it + model = self.model + elif hasattr(self, 'object') and self.object is not None: + # If this view is operating on a single object, use + # the class of that object + model = self.object.__class__ + else: + # Try to get a queryset and extract the model class + # from that + model = self.get_queryset().model return model_forms.modelform_factory(model) def get_form_kwargs(self): diff --git a/tests/regressiontests/generic_views/edit.py b/tests/regressiontests/generic_views/edit.py index 075cf3e551..923578d9d9 100644 --- a/tests/regressiontests/generic_views/edit.py +++ b/tests/regressiontests/generic_views/edit.py @@ -201,6 +201,25 @@ class UpdateViewTests(TestCase): except ImproperlyConfigured: pass + def test_update_get_object(self): + a = Author.objects.create( + name='Randall Munroe', + slug='randall-munroe', + ) + res = self.client.get('/edit/author/update/') + self.assertEqual(res.status_code, 200) + self.assertTrue(isinstance(res.context['form'], forms.ModelForm)) + self.assertEqual(res.context['object'], Author.objects.get(pk=a.pk)) + self.assertEqual(res.context['author'], Author.objects.get(pk=a.pk)) + self.assertTemplateUsed(res, 'generic_views/author_form.html') + + # Modification with both POST and PUT (browser compatible) + res = self.client.post('/edit/author/update/', + {'name': 'Randall Munroe (xkcd)', 'slug': 'randall-munroe'}) + self.assertEqual(res.status_code, 302) + self.assertRedirects(res, 'http://testserver/list/authors/') + self.assertQuerysetEqual(Author.objects.all(), ['']) + class DeleteViewTests(TestCase): urls = 'regressiontests.generic_views.urls' diff --git a/tests/regressiontests/generic_views/urls.py b/tests/regressiontests/generic_views/urls.py index e5d75d585c..c06b5d8a23 100644 --- a/tests/regressiontests/generic_views/urls.py +++ b/tests/regressiontests/generic_views/urls.py @@ -74,6 +74,8 @@ urlpatterns = patterns('', views.NaiveAuthorUpdate.as_view(success_url='/edit/author/%(id)d/update/')), (r'^edit/author/(?P\d+)/update/$', views.AuthorUpdate.as_view()), + (r'^edit/author/update/$', + views.OneAuthorUpdate.as_view()), (r'^edit/author/(?P\d+)/update/special/$', views.SpecializedAuthorUpdate.as_view()), (r'^edit/author/(?P\d+)/delete/naive/$', diff --git a/tests/regressiontests/generic_views/views.py b/tests/regressiontests/generic_views/views.py index e9be7c7ca9..9d2770cc5b 100644 --- a/tests/regressiontests/generic_views/views.py +++ b/tests/regressiontests/generic_views/views.py @@ -114,6 +114,13 @@ class AuthorUpdate(generic.UpdateView): success_url = '/list/authors/' +class OneAuthorUpdate(generic.UpdateView): + success_url = '/list/authors/' + + def get_object(self): + return Author.objects.get(pk=1) + + class SpecializedAuthorUpdate(generic.UpdateView): model = Author form_class = AuthorForm