Kaydet (Commit) 35d1cd0b authored tarafından Julien Phalip's avatar Julien Phalip Kaydeden (comit) Ramiro Morales

Fixed #19505 -- A more flexible implementation for customizable admin redirect urls.

Work by Julien Phalip.

Refs #8001, #18310, #19505. See also 0b908b92.
üst 4a71b842
This diff is collapsed.
...@@ -153,7 +153,7 @@ class UserAdmin(admin.ModelAdmin): ...@@ -153,7 +153,7 @@ class UserAdmin(admin.ModelAdmin):
'admin/auth/user/change_password.html', 'admin/auth/user/change_password.html',
context, current_app=self.admin_site.name) context, current_app=self.admin_site.name)
def response_add(self, request, obj, **kwargs): def response_add(self, request, obj, post_url_continue=None):
""" """
Determines the HttpResponse for the add_view stage. It mostly defers to Determines the HttpResponse for the add_view stage. It mostly defers to
its superclass implementation but is customized because the User model its superclass implementation but is customized because the User model
...@@ -166,7 +166,8 @@ class UserAdmin(admin.ModelAdmin): ...@@ -166,7 +166,8 @@ class UserAdmin(admin.ModelAdmin):
# * We are adding a user in a popup # * We are adding a user in a popup
if '_addanother' not in request.POST and '_popup' not in request.POST: if '_addanother' not in request.POST and '_popup' not in request.POST:
request.POST['_continue'] = 1 request.POST['_continue'] = 1
return super(UserAdmin, self).response_add(request, obj, **kwargs) return super(UserAdmin, self).response_add(request, obj,
post_url_continue)
admin.site.register(Group, GroupAdmin) admin.site.register(Group, GroupAdmin)
admin.site.register(User, UserAdmin) admin.site.register(User, UserAdmin)
...@@ -268,6 +268,12 @@ these changes. ...@@ -268,6 +268,12 @@ these changes.
* ``django.contrib.markup`` will be removed following an accelerated * ``django.contrib.markup`` will be removed following an accelerated
deprecation. deprecation.
* The value for the ``post_url_continue`` parameter in
``ModelAdmin.response_add()`` will have to be either ``None`` (to redirect
to the newly created object's edit page) or a pre-formatted url. String
formats, such as the previous default ``'../%s/'``, will not be accepted any
more.
1.7 1.7
--- ---
......
from functools import update_wrapper from functools import update_wrapper
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse
from django.db import models from django.db import models
from django.http import HttpResponseRedirect
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible
...@@ -49,41 +51,38 @@ class ActionAdmin(admin.ModelAdmin): ...@@ -49,41 +51,38 @@ class ActionAdmin(admin.ModelAdmin):
) + self.remove_url(view_name) ) + self.remove_url(view_name)
admin.site.register(Action, ActionAdmin) class Person(models.Model):
name = models.CharField(max_length=20)
class PersonAdmin(admin.ModelAdmin):
class Person(models.Model): def response_post_save(self, request, obj):
nick = models.CharField(max_length=20) return HttpResponseRedirect(
reverse('admin:admin_custom_urls_person_history', args=[obj.pk]))
class PersonAdmin(admin.ModelAdmin): class Car(models.Model):
"""A custom ModelAdmin that customizes the deprecated post_url_continue name = models.CharField(max_length=20)
argument to response_add()"""
def response_add(self, request, obj, post_url_continue='../%s/continue/',
continue_url=None, add_url=None, hasperm_url=None,
noperm_url=None):
return super(PersonAdmin, self).response_add(request, obj,
post_url_continue,
continue_url, add_url,
hasperm_url, noperm_url)
class CarAdmin(admin.ModelAdmin):
admin.site.register(Person, PersonAdmin) def response_add(self, request, obj, post_url_continue=None):
return super(CarAdmin, self).response_add(
request, obj, post_url_continue=reverse('admin:admin_custom_urls_car_history', args=[obj.pk]))
class City(models.Model): class CarDeprecated(models.Model):
""" This class must be removed in Django 1.6 """
name = models.CharField(max_length=20) name = models.CharField(max_length=20)
class CarDeprecatedAdmin(admin.ModelAdmin):
class CityAdmin(admin.ModelAdmin): """ This class must be removed in Django 1.6 """
"""A custom ModelAdmin that redirects to the changelist when the user def response_add(self, request, obj, post_url_continue=None):
presses the 'Save and add another' button when adding a model instance.""" return super(CarDeprecatedAdmin, self).response_add(
def response_add(self, request, obj, request, obj, post_url_continue='../%s/history/')
add_another_url='admin:admin_custom_urls_city_changelist',
**kwargs):
return super(CityAdmin, self).response_add(request, obj,
add_another_url=add_another_url,
**kwargs)
admin.site.register(City, CityAdmin) admin.site.register(Action, ActionAdmin)
admin.site.register(Person, PersonAdmin)
admin.site.register(Car, CarAdmin)
admin.site.register(CarDeprecated, CarDeprecatedAdmin)
\ No newline at end of file
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
import warnings import warnings
from django.contrib.admin.util import quote from django.contrib.admin.util import quote
...@@ -8,7 +7,7 @@ from django.template.response import TemplateResponse ...@@ -8,7 +7,7 @@ from django.template.response import TemplateResponse
from django.test import TestCase from django.test import TestCase
from django.test.utils import override_settings from django.test.utils import override_settings
from .models import Action, Person, City from .models import Action, Person, Car, CarDeprecated
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
...@@ -86,8 +85,8 @@ class AdminCustomUrlsTest(TestCase): ...@@ -86,8 +85,8 @@ class AdminCustomUrlsTest(TestCase):
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class CustomUrlsWorkflowTests(TestCase): class CustomRedirects(TestCase):
fixtures = ['users.json'] fixtures = ['users.json', 'actions.json']
def setUp(self): def setUp(self):
self.client.login(username='super', password='secret') self.client.login(username='super', password='secret')
...@@ -95,33 +94,49 @@ class CustomUrlsWorkflowTests(TestCase): ...@@ -95,33 +94,49 @@ class CustomUrlsWorkflowTests(TestCase):
def tearDown(self): def tearDown(self):
self.client.logout() self.client.logout()
def test_old_argument_deprecation(self): def test_post_save_redirect(self):
"""Test reporting of post_url_continue deprecation.""" """
post_data = { Ensures that ModelAdmin.response_post_save() controls the redirection
'nick': 'johndoe', after the 'Save' button has been pressed.
} Refs 8001, 18310, 19505.
cnt = Person.objects.count() """
with warnings.catch_warnings(record=True) as w: post_data = { 'name': 'John Doe', }
warnings.simplefilter("always") self.assertEqual(Person.objects.count(), 0)
response = self.client.post(reverse('admin:admin_custom_urls_person_add'), post_data) response = self.client.post(
self.assertEqual(response.status_code, 302) reverse('admin:admin_custom_urls_person_add'), post_data)
self.assertEqual(Person.objects.count(), cnt + 1) persons = Person.objects.all()
# We should get a DeprecationWarning self.assertEqual(len(persons), 1)
self.assertEqual(len(w), 1) self.assertRedirects(
self.assertTrue(isinstance(w[0].message, DeprecationWarning)) response, reverse('admin:admin_custom_urls_person_history', args=[persons[0].pk]))
def test_custom_add_another_redirect(self): def test_post_url_continue(self):
"""Test customizability of post-object-creation redirect URL.""" """
post_data = { Ensures that the ModelAdmin.response_add()'s parameter `post_url_continue`
'name': 'Rome', controls the redirection after an object has been created.
'_addanother': '1', """
} post_data = { 'name': 'SuperFast', '_continue': '1' }
cnt = City.objects.count() self.assertEqual(Car.objects.count(), 0)
response = self.client.post(
reverse('admin:admin_custom_urls_car_add'), post_data)
cars = Car.objects.all()
self.assertEqual(len(cars), 1)
self.assertRedirects(
response, reverse('admin:admin_custom_urls_car_history', args=[cars[0].pk]))
def test_post_url_continue_string_formats(self):
"""
Ensures that string formats are accepted for post_url_continue. This
is a deprecated functionality that will be removed in Django 1.6 along
with this test.
"""
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
# POST to the view whose post-object-creation redir URL argument we post_data = { 'name': 'SuperFast', '_continue': '1' }
# are customizing (object creation) self.assertEqual(Car.objects.count(), 0)
response = self.client.post(reverse('admin:admin_custom_urls_city_add'), post_data) response = self.client.post(
self.assertEqual(City.objects.count(), cnt + 1) reverse('admin:admin_custom_urls_cardeprecated_add'), post_data)
# Check that it redirected to the URL we set cars = CarDeprecated.objects.all()
self.assertRedirects(response, reverse('admin:admin_custom_urls_city_changelist')) self.assertEqual(len(cars), 1)
self.assertEqual(len(w), 0) # We should get no DeprecationWarning self.assertRedirects(
response, reverse('admin:admin_custom_urls_cardeprecated_history', args=[cars[0].pk]))
self.assertEqual(len(w), 1)
self.assertTrue(isinstance(w[0].message, DeprecationWarning))
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment