summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Amalthea Magnuson <markus.magnuson@gmail.com>2016-04-03 16:50:01 +0200
committerTim Graham <timograham@gmail.com>2016-04-20 11:31:44 -0400
commit08cd6a0e56bac04e322388e7059072ad98db303c (patch)
tree615d175fcf55f2d1ebe02a5895aacb1104b7ec03
parentcb65e62c84dd8f6b412151e81cf665975143d397 (diff)
Fixed #16327 -- Redirected "Save as new" to change view instead of the changelist.
-rw-r--r--django/contrib/admin/options.py7
-rw-r--r--docs/ref/contrib/admin/index.txt10
-rw-r--r--docs/releases/1.10.txt7
-rw-r--r--tests/admin_views/admin.py1
-rw-r--r--tests/admin_views/tests.py25
5 files changed, 48 insertions, 2 deletions
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 9bc736ed4e..22209416d6 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -487,6 +487,7 @@ class ModelAdmin(BaseModelAdmin):
search_fields = ()
date_hierarchy = None
save_as = False
+ save_as_continue = True
save_on_top = False
paginator = Paginator
preserve_filters = True
@@ -1102,7 +1103,11 @@ class ModelAdmin(BaseModelAdmin):
'popup_response_data': popup_response_data,
})
- elif "_continue" in request.POST:
+ elif "_continue" in request.POST or (
+ # Redirecting after "Save as new".
+ "_saveasnew" in request.POST and self.save_as_continue and
+ self.has_change_permission(request, obj)
+ ):
msg = format_html(
_('The {name} "{obj}" was added successfully. You may edit it again below.'),
**msg_dict
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index 284d6aa62d..4f5cc22de1 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -1146,6 +1146,16 @@ subclass::
By default, ``save_as`` is set to ``False``.
+.. attribute:: ModelAdmin.save_as_continue
+
+ .. versionadded:: 1.10
+
+ When :attr:`save_as=True <save_as>`, the default redirect after saving the
+ new object is to the change view for that object. If you set
+ ``save_as_continue=False``, the redirect will be to the changelist view.
+
+ By default, ``save_as_continue`` is set to ``True``.
+
.. attribute:: ModelAdmin.save_on_top
Set ``save_on_top`` to add save buttons across the top of your admin change
diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt
index c2d34c5992..05f3c20b1a 100644
--- a/docs/releases/1.10.txt
+++ b/docs/releases/1.10.txt
@@ -753,6 +753,13 @@ Miscellaneous
model, you must convert them to attributes or properties as described in
:ref:`the deprecation note <user-is-auth-anon-deprecation>`.
+* When using :attr:`ModelAdmin.save_as=True
+ <django.contrib.admin.ModelAdmin.save_as>`, the "Save as new" button now
+ redirects to the change view for the new object instead of to the model's
+ changelist. If you need the previous behavior, set the new
+ :attr:`ModelAdmin.save_as_continue
+ <django.contrib.admin.ModelAdmin.save_as_continue>` attribute to ``False``.
+
.. _deprecated-features-1.10:
Features deprecated in 1.10
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index f4dfb91bef..31f41515bb 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -1013,6 +1013,7 @@ site2.register(
list_editable=['parent'],
raw_id_fields=['parent'],
)
+site2.register(Person, save_as_continue=False)
site7 = admin.AdminSite(name="admin7")
site7.register(Article, ArticleAdmin2)
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 48ce1770fb..5c0d5ed51c 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -1119,9 +1119,23 @@ class SaveAsTests(TestCase):
def test_save_as_duplication(self):
"""Ensure save as actually creates a new person"""
post_data = {'_saveasnew': '', 'name': 'John M', 'gender': 1, 'age': 42}
- self.client.post(reverse('admin:admin_views_person_change', args=(self.per1.pk,)), post_data)
+ response = self.client.post(reverse('admin:admin_views_person_change', args=(self.per1.pk,)), post_data)
self.assertEqual(len(Person.objects.filter(name='John M')), 1)
self.assertEqual(len(Person.objects.filter(id=self.per1.pk)), 1)
+ new_person = Person.objects.latest('id')
+ self.assertRedirects(response, reverse('admin:admin_views_person_change', args=(new_person.pk,)))
+
+ def test_save_as_continue_false(self):
+ """
+ Saving a new object using "Save as new" redirects to the changelist
+ instead of the change view when ModelAdmin.save_as_continue=False.
+ """
+ post_data = {'_saveasnew': '', 'name': 'John M', 'gender': 1, 'age': 42}
+ url = reverse('admin:admin_views_person_change', args=(self.per1.pk,), current_app=site2.name)
+ response = self.client.post(url, post_data)
+ self.assertEqual(len(Person.objects.filter(name='John M')), 1)
+ self.assertEqual(len(Person.objects.filter(id=self.per1.pk)), 1)
+ self.assertRedirects(response, reverse('admin:admin_views_person_changelist', current_app=site2.name))
def test_save_as_new_with_validation_errors(self):
"""
@@ -1689,6 +1703,15 @@ class AdminViewPermissionsTest(TestCase):
self.assertEqual(post.status_code, 403)
self.assertEqual(Article.objects.count(), article_count)
+ # User with both add and change permissions should be redirected to the
+ # change page for the newly created object.
+ article_count = Article.objects.count()
+ self.client.force_login(self.superuser)
+ post = self.client.post(article_change_url, change_dict_save_as_new)
+ self.assertEqual(Article.objects.count(), article_count + 1)
+ new_article = Article.objects.latest('id')
+ self.assertRedirects(post, reverse('admin:admin_views_article_change', args=(new_article.pk,)))
+
def test_delete_view(self):
"""Delete view should restrict access and actually delete items."""
delete_dict = {'post': 'yes'}