From ab8965c428ed4390c006c3375ba30595008fa525 Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Fri, 8 Aug 2008 18:07:33 +0000 Subject: [PATCH] Added a few force_unicode() calls around objects in the admin. Required for Python 2.3 compatibility. Patch from nfg. Refs #8151, #8153. git-svn-id: http://code.djangoproject.com/svn/django/trunk@8236 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/admin/options.py | 4 +- tests/regressiontests/admin_views/models.py | 14 ++- tests/regressiontests/admin_views/tests.py | 101 ++++++++++---------- 3 files changed, 63 insertions(+), 56 deletions(-) diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index d161c58e64..b373200d8c 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -358,7 +358,7 @@ class ModelAdmin(BaseModelAdmin): pk_value = new_object._get_pk_val() LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(self.model).id, pk_value, force_unicode(new_object), ADDITION) - msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': new_object} + msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(new_object)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if request.POST.has_key("_continue"): @@ -428,7 +428,7 @@ class ModelAdmin(BaseModelAdmin): change_message = _('No fields changed.') LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(self.model).id, pk_value, force_unicode(new_object), CHANGE, change_message) - msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': new_object} + msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(new_object)} if request.POST.has_key("_continue"): request.user.message_set.create(message=msg + ' ' + _("You may edit it again below.")) if request.REQUEST.has_key('_popup'): diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py index 2062107397..a8fc9467ba 100644 --- a/tests/regressiontests/admin_views/models.py +++ b/tests/regressiontests/admin_views/models.py @@ -3,7 +3,7 @@ from django.contrib import admin class Section(models.Model): """ - A simple section that links to articles, to test linking to related items + A simple section that links to articles, to test linking to related items in admin views. """ name = models.CharField(max_length=100) @@ -12,14 +12,18 @@ class Article(models.Model): """ A simple article to test admin views. Test backwards compatibility. """ + title = models.CharField(max_length=100) content = models.TextField() date = models.DateTimeField() section = models.ForeignKey(Section) + def __unicode__(self): + return self.title + class ArticleAdmin(admin.ModelAdmin): list_display = ('content', 'date') list_filter = ('date',) - + def changelist_view(self, request): "Test that extra_context works" return super(ArticleAdmin, self).changelist_view( @@ -40,7 +44,7 @@ class CustomArticleAdmin(admin.ModelAdmin): change_form_template = 'custom_admin/change_form.html' object_history_template = 'custom_admin/object_history.html' delete_confirmation_template = 'custom_admin/delete_confirmation.html' - + def changelist_view(self, request): "Test that extra_context works" return super(CustomArticleAdmin, self).changelist_view( @@ -51,10 +55,10 @@ class CustomArticleAdmin(admin.ModelAdmin): class ModelWithStringPrimaryKey(models.Model): id = models.CharField(max_length=255, primary_key=True) - + def __unicode__(self): return self.id - + admin.site.register(Article, ArticleAdmin) admin.site.register(CustomArticle, CustomArticleAdmin) admin.site.register(Section) diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py index acdf9f5742..c7a8a2eeb8 100644 --- a/tests/regressiontests/admin_views/tests.py +++ b/tests/regressiontests/admin_views/tests.py @@ -1,3 +1,4 @@ +# coding: utf-8 from django.test import TestCase from django.contrib.auth.models import User, Permission @@ -17,35 +18,35 @@ def get_perm(Model, perm): class AdminViewPermissionsTest(TestCase): """Tests for Admin Views Permissions.""" - + fixtures = ['admin-views-users.xml'] - + def setUp(self): """Test setup.""" - # Setup permissions, for our users who can add, change, and delete. + # Setup permissions, for our users who can add, change, and delete. # We can't put this into the fixture, because the content type id # and the permission id could be different on each run of the test. - + opts = Article._meta - + # User who can add Articles add_user = User.objects.get(username='adduser') add_user.user_permissions.add(get_perm(Article, opts.get_add_permission())) - + # User who can change Articles change_user = User.objects.get(username='changeuser') change_user.user_permissions.add(get_perm(Article, opts.get_change_permission())) - + # User who can delete Articles delete_user = User.objects.get(username='deleteuser') delete_user.user_permissions.add(get_perm(Article, opts.get_delete_permission())) - + delete_user.user_permissions.add(get_perm(Section, Section._meta.get_delete_permission())) - + # login POST dicts self.super_login = {'post_data': _encode_post_data({}), LOGIN_FORM_KEY: 1, @@ -81,7 +82,7 @@ class AdminViewPermissionsTest(TestCase): If you leave off the trailing slash, app should redirect and add it. """ self.client.post('/test_admin/admin/', self.super_login) - + request = self.client.get( '/test_admin/admin/admin_views/article/add' ) @@ -92,9 +93,9 @@ class AdminViewPermissionsTest(TestCase): def testLogin(self): """ Make sure only staff members can log in. - + Successful posts to the login page will redirect to the orignal url. - Unsuccessfull attempts will continue to render the login page with + Unsuccessfull attempts will continue to render the login page with a 200 status code. """ # Super User @@ -104,7 +105,7 @@ class AdminViewPermissionsTest(TestCase): self.assertRedirects(login, '/test_admin/admin/') self.failIf(login.context) self.client.get('/test_admin/admin/logout/') - + # Test if user enters e-mail address request = self.client.get('/test_admin/admin/') self.failUnlessEqual(request.status_code, 200) @@ -118,7 +119,7 @@ class AdminViewPermissionsTest(TestCase): # check to ensure if there are multiple e-mail addresses a user doesn't get a 500 login = self.client.post('/test_admin/admin/', self.super_email_login) self.assertContains(login, "Usernames cannot contain the '@' character") - + # Add User request = self.client.get('/test_admin/admin/') self.failUnlessEqual(request.status_code, 200) @@ -126,7 +127,7 @@ class AdminViewPermissionsTest(TestCase): self.assertRedirects(login, '/test_admin/admin/') self.failIf(login.context) self.client.get('/test_admin/admin/logout/') - + # Change User request = self.client.get('/test_admin/admin/') self.failUnlessEqual(request.status_code, 200) @@ -134,7 +135,7 @@ class AdminViewPermissionsTest(TestCase): self.assertRedirects(login, '/test_admin/admin/') self.failIf(login.context) self.client.get('/test_admin/admin/logout/') - + # Delete User request = self.client.get('/test_admin/admin/') self.failUnlessEqual(request.status_code, 200) @@ -142,7 +143,7 @@ class AdminViewPermissionsTest(TestCase): self.assertRedirects(login, '/test_admin/admin/') self.failIf(login.context) self.client.get('/test_admin/admin/logout/') - + # Regular User should not be able to login. request = self.client.get('/test_admin/admin/') self.failUnlessEqual(request.status_code, 200) @@ -153,11 +154,12 @@ class AdminViewPermissionsTest(TestCase): def testAddView(self): """Test add view restricts access and actually adds items.""" - - add_dict = {'content': '

great article

', + + add_dict = {'title' : 'Døm ikke', + 'content': '

great article

', 'date_0': '2008-03-18', 'date_1': '10:54:39', 'section': 1} - + # Change User should not have access to add articles self.client.get('/test_admin/admin/') self.client.post('/test_admin/admin/', self.changeuser_login) @@ -168,7 +170,7 @@ class AdminViewPermissionsTest(TestCase): self.failUnlessEqual(post.status_code, 403) self.failUnlessEqual(Article.objects.all().count(), 1) self.client.get('/test_admin/admin/logout/') - + # Add user may login and POST to add view, then redirect to admin root self.client.get('/test_admin/admin/') self.client.post('/test_admin/admin/', self.adduser_login) @@ -176,7 +178,7 @@ class AdminViewPermissionsTest(TestCase): self.assertRedirects(post, '/test_admin/admin/') self.failUnlessEqual(Article.objects.all().count(), 2) self.client.get('/test_admin/admin/logout/') - + # Super can add too, but is redirected to the change list view self.client.get('/test_admin/admin/') self.client.post('/test_admin/admin/', self.super_login) @@ -184,7 +186,7 @@ class AdminViewPermissionsTest(TestCase): self.assertRedirects(post, '/test_admin/admin/admin_views/article/') self.failUnlessEqual(Article.objects.all().count(), 3) self.client.get('/test_admin/admin/logout/') - + # Check and make sure that if user expires, data still persists post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict) self.assertContains(post, 'Please log in again, because your session has expired.') @@ -196,11 +198,12 @@ class AdminViewPermissionsTest(TestCase): def testChangeView(self): """Change view should restrict access and allow users to edit items.""" - - change_dict = {'content': '

edited article

', - 'date_0': '2008-03-18', 'date_1': '10:54:39', - 'section': 1} - + + change_dict = {'title' : 'Ikke fordømt', + 'content': '

edited article

', + 'date_0': '2008-03-18', 'date_1': '10:54:39', + 'section': 1} + # add user shoud not be able to view the list of article or change any of them self.client.get('/test_admin/admin/') self.client.post('/test_admin/admin/', self.adduser_login) @@ -211,7 +214,7 @@ class AdminViewPermissionsTest(TestCase): post = self.client.post('/test_admin/admin/admin_views/article/1/', change_dict) self.failUnlessEqual(post.status_code, 403) self.client.get('/test_admin/admin/logout/') - + # change user can view all items and edit them self.client.get('/test_admin/admin/') self.client.post('/test_admin/admin/', self.changeuser_login) @@ -227,17 +230,17 @@ class AdminViewPermissionsTest(TestCase): def testCustomModelAdminTemplates(self): self.client.get('/test_admin/admin/') self.client.post('/test_admin/admin/', self.super_login) - + # Test custom change list template with custom extra context request = self.client.get('/test_admin/admin/admin_views/customarticle/') self.failUnlessEqual(request.status_code, 200) self.assert_("var hello = 'Hello!';" in request.content) self.assertTemplateUsed(request, 'custom_admin/change_list.html') - + # Test custom change form template request = self.client.get('/test_admin/admin/admin_views/customarticle/add/') self.assertTemplateUsed(request, 'custom_admin/change_form.html') - + # Add an article so we can test delete and history views post = self.client.post('/test_admin/admin/admin_views/customarticle/add/', { 'content': '

great article

', @@ -246,27 +249,27 @@ class AdminViewPermissionsTest(TestCase): }) self.assertRedirects(post, '/test_admin/admin/admin_views/customarticle/') self.failUnlessEqual(CustomArticle.objects.all().count(), 1) - + # Test custom delete and object history templates request = self.client.get('/test_admin/admin/admin_views/customarticle/1/delete/') self.assertTemplateUsed(request, 'custom_admin/delete_confirmation.html') request = self.client.get('/test_admin/admin/admin_views/customarticle/1/history/') self.assertTemplateUsed(request, 'custom_admin/object_history.html') - + self.client.get('/test_admin/admin/logout/') def testCustomAdminSiteTemplates(self): from django.contrib import admin self.assertEqual(admin.site.index_template, None) self.assertEqual(admin.site.login_template, None) - + self.client.get('/test_admin/admin/logout/') request = self.client.get('/test_admin/admin/') self.assertTemplateUsed(request, 'admin/login.html') self.client.post('/test_admin/admin/', self.changeuser_login) request = self.client.get('/test_admin/admin/') self.assertTemplateUsed(request, 'admin/index.html') - + self.client.get('/test_admin/admin/logout/') admin.site.login_template = 'custom_admin/login.html' admin.site.index_template = 'custom_admin/index.html' @@ -277,7 +280,7 @@ class AdminViewPermissionsTest(TestCase): request = self.client.get('/test_admin/admin/') self.assertTemplateUsed(request, 'custom_admin/index.html') self.assert_('Hello from a custom index template' in request.content) - + # Finally, using monkey patching check we can inject custom_context arguments in to index original_index = admin.site.index def index(*args, **kwargs): @@ -287,7 +290,7 @@ class AdminViewPermissionsTest(TestCase): request = self.client.get('/test_admin/admin/') self.assertTemplateUsed(request, 'custom_admin/index.html') self.assert_('Hello from a custom index template *bar*' in request.content) - + self.client.get('/test_admin/admin/logout/') del admin.site.index # Resets to using the original admin.site.login_template = None @@ -295,9 +298,9 @@ class AdminViewPermissionsTest(TestCase): def testDeleteView(self): """Delete view should restrict access and actually delete items.""" - + delete_dict = {'post': 'yes'} - + # add user shoud not be able to delete articles self.client.get('/test_admin/admin/') self.client.post('/test_admin/admin/', self.adduser_login) @@ -307,14 +310,14 @@ class AdminViewPermissionsTest(TestCase): self.failUnlessEqual(post.status_code, 403) self.failUnlessEqual(Article.objects.all().count(), 1) self.client.get('/test_admin/admin/logout/') - + # Delete user can delete self.client.get('/test_admin/admin/') self.client.post('/test_admin/admin/', self.deleteuser_login) response = self.client.get('/test_admin/admin/admin_views/section/1/delete/') # test response contains link to related Article self.assertContains(response, "admin_views/article/1/") - + response = self.client.get('/test_admin/admin/admin_views/article/1/delete/') self.failUnlessEqual(response.status_code, 200) post = self.client.post('/test_admin/admin/admin_views/article/1/delete/', delete_dict) @@ -324,37 +327,37 @@ class AdminViewPermissionsTest(TestCase): class AdminViewStringPrimaryKeyTest(TestCase): fixtures = ['admin-views-users.xml', 'string-primary-key.xml'] - + def __init__(self, *args): super(AdminViewStringPrimaryKeyTest, self).__init__(*args) self.pk = """abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 -_.!~*'() ;/?:@&=+$, <>#%" {}|\^[]`""" - + def setUp(self): self.client.login(username='super', password='secret') content_type_pk = ContentType.objects.get_for_model(ModelWithStringPrimaryKey).pk LogEntry.objects.log_action(100, content_type_pk, self.pk, self.pk, 2, change_message='') - + def tearDown(self): self.client.logout() - + def test_get_change_view(self): "Retrieving the object using urlencoded form of primary key should work" response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/' % quote(self.pk)) self.assertContains(response, escape(self.pk)) self.failUnlessEqual(response.status_code, 200) - + def test_changelist_to_changeform_link(self): "The link from the changelist referring to the changeform of the object should be quoted" response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/') should_contain = """%s""" % (quote(self.pk), escape(self.pk)) self.assertContains(response, should_contain) - + def test_recentactions_link(self): "The link from the recent actions list referring to the changeform of the object should be quoted" response = self.client.get('/test_admin/admin/') should_contain = """%s""" % (quote(self.pk), escape(self.pk)) self.assertContains(response, should_contain) - + def test_deleteconfirmation_link(self): "The link from the delete confirmation page referring back to the changeform of the object should be quoted" response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/delete/' % quote(self.pk))