Fixed #19044 -- Made `DeletionMixin` interpolate its `success_url`.

Thanks to nxvl and slurms for the initial patch, ptone for the review
and timo for the documentation tweaks.
This commit is contained in:
Simon Charette 2013-02-11 02:39:14 -05:00
parent 5ce6a7cea2
commit a10f390804
5 changed files with 29 additions and 8 deletions

View File

@ -242,8 +242,9 @@ class DeletionMixin(object):
redirects to the success URL. redirects to the success URL.
""" """
self.object = self.get_object() self.object = self.get_object()
success_url = self.get_success_url()
self.object.delete() self.object.delete()
return HttpResponseRedirect(self.get_success_url()) return HttpResponseRedirect(success_url)
# Add support for browsers which only accept GET and POST for now. # Add support for browsers which only accept GET and POST for now.
def post(self, *args, **kwargs): def post(self, *args, **kwargs):
@ -251,7 +252,7 @@ class DeletionMixin(object):
def get_success_url(self): def get_success_url(self):
if self.success_url: if self.success_url:
return self.success_url return self.success_url % self.object.__dict__
else: else:
raise ImproperlyConfigured( raise ImproperlyConfigured(
"No URL to redirect to. Provide a success_url.") "No URL to redirect to. Provide a success_url.")

View File

@ -201,6 +201,13 @@ ProcessFormView
The url to redirect to when the nominated object has been The url to redirect to when the nominated object has been
successfully deleted. successfully deleted.
.. versionadded:: 1.6
``success_url`` may contain dictionary string formatting, which
will be interpolated against the object's field attributes. For
example, you could use ``success_url="/parent/%(parent_id)s/"`` to
redirect to a URL composed out of the ``parent_id`` field on a model.
.. method:: get_success_url(obj) .. method:: get_success_url(obj)
Returns the url to redirect to when the nominated object has been Returns the url to redirect to when the nominated object has been

View File

@ -64,6 +64,10 @@ Minor features
:attr:`~django.core.management.BaseCommand.leave_locale_alone` internal :attr:`~django.core.management.BaseCommand.leave_locale_alone` internal
option. See :ref:`management-commands-and-locales` for more details. option. See :ref:`management-commands-and-locales` for more details.
* The :attr:`~django.views.generic.edit.DeletionMixin.success_url` of
:class:`~django.views.generic.edit.DeletionMixin` is now interpolated with
its ``object``\'s ``__dict__``.
Backwards incompatible changes in 1.6 Backwards incompatible changes in 1.6
===================================== =====================================

View File

@ -13,12 +13,12 @@ from .models import Artist, Author
class FormMixinTests(TestCase): class FormMixinTests(TestCase):
def test_initial_data(self): def test_initial_data(self):
""" Test instance independence of initial data dict (see #16138) """ """ Test instance independence of initial data dict (see #16138) """
initial_1 = FormMixin().get_initial() initial_1 = FormMixin().get_initial()
initial_1['foo'] = 'bar' initial_1['foo'] = 'bar'
initial_2 = FormMixin().get_initial() initial_2 = FormMixin().get_initial()
self.assertNotEqual(initial_1, initial_2) self.assertNotEqual(initial_1, initial_2)
class BasicFormTests(TestCase): class BasicFormTests(TestCase):
@ -283,6 +283,13 @@ class DeleteViewTests(TestCase):
self.assertRedirects(res, 'http://testserver/edit/authors/create/') self.assertRedirects(res, 'http://testserver/edit/authors/create/')
self.assertQuerysetEqual(Author.objects.all(), []) self.assertQuerysetEqual(Author.objects.all(), [])
def test_delete_with_interpolated_redirect(self):
a = Author.objects.create(**{'name': 'Randall Munroe', 'slug': 'randall-munroe'})
res = self.client.post('/edit/author/%d/delete/interpolate_redirect/' % a.pk)
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/edit/authors/create/?deleted=%d' % a.pk)
self.assertQuerysetEqual(Author.objects.all(), [])
def test_delete_with_special_properties(self): def test_delete_with_special_properties(self):
a = Author.objects.create(**{'name': 'Randall Munroe', 'slug': 'randall-munroe'}) a = Author.objects.create(**{'name': 'Randall Munroe', 'slug': 'randall-munroe'})
res = self.client.get('/edit/author/%d/delete/special/' % a.pk) res = self.client.get('/edit/author/%d/delete/special/' % a.pk)

View File

@ -97,6 +97,8 @@ urlpatterns = patterns('',
views.NaiveAuthorDelete.as_view()), views.NaiveAuthorDelete.as_view()),
(r'^edit/author/(?P<pk>\d+)/delete/redirect/$', (r'^edit/author/(?P<pk>\d+)/delete/redirect/$',
views.NaiveAuthorDelete.as_view(success_url='/edit/authors/create/')), views.NaiveAuthorDelete.as_view(success_url='/edit/authors/create/')),
(r'^edit/author/(?P<pk>\d+)/delete/interpolate_redirect/$',
views.NaiveAuthorDelete.as_view(success_url='/edit/authors/create/?deleted=%(id)s')),
(r'^edit/author/(?P<pk>\d+)/delete/$', (r'^edit/author/(?P<pk>\d+)/delete/$',
views.AuthorDelete.as_view()), views.AuthorDelete.as_view()),
(r'^edit/author/(?P<pk>\d+)/delete/special/$', (r'^edit/author/(?P<pk>\d+)/delete/special/$',