summaryrefslogtreecommitdiff
path: root/tests/regressiontests/admin_views
diff options
context:
space:
mode:
authorJustin Bronn <jbronn@gmail.com>2008-07-19 13:30:47 +0000
committerJustin Bronn <jbronn@gmail.com>2008-07-19 13:30:47 +0000
commit149e731c3c5a2cc96b7d3c72070401df6c2a238e (patch)
tree2a819f695246ab36139b7f8846085c9df1563bd8 /tests/regressiontests/admin_views
parent5bf3565a263533e37b2e1217e8d447cb7e02f5b4 (diff)
gis: Merged revisions 7921,7926-7928,7938-7941,7945-7947,7949-7950,7952,7955-7956,7961,7964-7968,7970-7978 via svnmerge from trunk.
This includes the newforms-admin branch, and thus is backwards-incompatible. The geographic admin is _not_ in this changeset, and is forthcoming. git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@7979 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests/regressiontests/admin_views')
-rw-r--r--tests/regressiontests/admin_views/__init__.py0
-rw-r--r--tests/regressiontests/admin_views/fixtures/admin-views-users.xml81
-rw-r--r--tests/regressiontests/admin_views/fixtures/string-primary-key.xml6
-rw-r--r--tests/regressiontests/admin_views/models.py61
-rw-r--r--tests/regressiontests/admin_views/tests.py362
-rw-r--r--tests/regressiontests/admin_views/urls.py7
6 files changed, 517 insertions, 0 deletions
diff --git a/tests/regressiontests/admin_views/__init__.py b/tests/regressiontests/admin_views/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/admin_views/__init__.py
diff --git a/tests/regressiontests/admin_views/fixtures/admin-views-users.xml b/tests/regressiontests/admin_views/fixtures/admin-views-users.xml
new file mode 100644
index 0000000000..8d6c62b58f
--- /dev/null
+++ b/tests/regressiontests/admin_views/fixtures/admin-views-users.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0">
+ <object pk="100" model="auth.user">
+ <field type="CharField" name="username">super</field>
+ <field type="CharField" name="first_name">Super</field>
+ <field type="CharField" name="last_name">User</field>
+ <field type="CharField" name="email">super@example.com</field>
+ <field type="CharField" name="password">sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158</field>
+ <field type="BooleanField" name="is_staff">True</field>
+ <field type="BooleanField" name="is_active">True</field>
+ <field type="BooleanField" name="is_superuser">True</field>
+ <field type="DateTimeField" name="last_login">2007-05-30 13:20:10</field>
+ <field type="DateTimeField" name="date_joined">2007-05-30 13:20:10</field>
+ <field to="auth.group" name="groups" rel="ManyToManyRel"></field>
+ <field to="auth.permission" name="user_permissions" rel="ManyToManyRel"></field>
+ </object>
+ <object pk="101" model="auth.user">
+ <field type="CharField" name="username">adduser</field>
+ <field type="CharField" name="first_name">Add</field>
+ <field type="CharField" name="last_name">User</field>
+ <field type="CharField" name="email">auser@example.com</field>
+ <field type="CharField" name="password">sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158</field>
+ <field type="BooleanField" name="is_staff">True</field>
+ <field type="BooleanField" name="is_active">True</field>
+ <field type="BooleanField" name="is_superuser">False</field>
+ <field type="DateTimeField" name="last_login">2007-05-30 13:20:10</field>
+ <field type="DateTimeField" name="date_joined">2007-05-30 13:20:10</field>
+ <field to="auth.group" name="groups" rel="ManyToManyRel"></field>
+ <field to="auth.permission" name="user_permissions" rel="ManyToManyRel"></field>
+ </object>
+ <object pk="102" model="auth.user">
+ <field type="CharField" name="username">changeuser</field>
+ <field type="CharField" name="first_name">Change</field>
+ <field type="CharField" name="last_name">User</field>
+ <field type="CharField" name="email">cuser@example.com</field>
+ <field type="CharField" name="password">sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158</field>
+ <field type="BooleanField" name="is_staff">True</field>
+ <field type="BooleanField" name="is_active">True</field>
+ <field type="BooleanField" name="is_superuser">False</field>
+ <field type="DateTimeField" name="last_login">2007-05-30 13:20:10</field>
+ <field type="DateTimeField" name="date_joined">2007-05-30 13:20:10</field>
+ <field to="auth.group" name="groups" rel="ManyToManyRel"></field>
+ <field to="auth.permission" name="user_permissions" rel="ManyToManyRel"></field>
+ </object>
+ <object pk="103" model="auth.user">
+ <field type="CharField" name="username">deleteuser</field>
+ <field type="CharField" name="first_name">Delete</field>
+ <field type="CharField" name="last_name">User</field>
+ <field type="CharField" name="email">duser@example.com</field>
+ <field type="CharField" name="password">sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158</field>
+ <field type="BooleanField" name="is_staff">True</field>
+ <field type="BooleanField" name="is_active">True</field>
+ <field type="BooleanField" name="is_superuser">False</field>
+ <field type="DateTimeField" name="last_login">2007-05-30 13:20:10</field>
+ <field type="DateTimeField" name="date_joined">2007-05-30 13:20:10</field>
+ <field to="auth.group" name="groups" rel="ManyToManyRel"></field>
+ <field to="auth.permission" name="user_permissions" rel="ManyToManyRel"></field>
+ </object>
+ <object pk="104" model="auth.user">
+ <field type="CharField" name="username">joepublic</field>
+ <field type="CharField" name="first_name">Joe</field>
+ <field type="CharField" name="last_name">Public</field>
+ <field type="CharField" name="email">joepublic@example.com</field>
+ <field type="CharField" name="password">sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158</field>
+ <field type="BooleanField" name="is_staff">False</field>
+ <field type="BooleanField" name="is_active">True</field>
+ <field type="BooleanField" name="is_superuser">False</field>
+ <field type="DateTimeField" name="last_login">2007-05-30 13:20:10</field>
+ <field type="DateTimeField" name="date_joined">2007-05-30 13:20:10</field>
+ <field to="auth.group" name="groups" rel="ManyToManyRel"></field>
+ <field to="auth.permission" name="user_permissions" rel="ManyToManyRel"></field>
+ </object>
+ <object pk="1" model="admin_views.section">
+ <field type="CharField" name="name">Test section</field>
+ </object>
+ <object pk="1" model="admin_views.article">
+ <field type="TextField" name="content">&lt;p&gt;test content&lt;/p&gt;</field>
+ <field type="DateTimeField" name="date">2008-03-18 11:54:58</field>
+ <field to="admin_views.section" name="section" rel="ManyToOneRel">1</field>
+ </object>
+</django-objects> \ No newline at end of file
diff --git a/tests/regressiontests/admin_views/fixtures/string-primary-key.xml b/tests/regressiontests/admin_views/fixtures/string-primary-key.xml
new file mode 100644
index 0000000000..8e1dbf047f
--- /dev/null
+++ b/tests/regressiontests/admin_views/fixtures/string-primary-key.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0">
+ <object pk="1" model="admin_views.modelwithstringprimarykey">
+ <field type="CharField" name="id"><![CDATA[abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 -_.!~*'() ;/?:@&=+$, <>#%" {}|\^[]`]]></field>
+ </object>
+</django-objects> \ No newline at end of file
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
new file mode 100644
index 0000000000..2062107397
--- /dev/null
+++ b/tests/regressiontests/admin_views/models.py
@@ -0,0 +1,61 @@
+from django.db import models
+from django.contrib import admin
+
+class Section(models.Model):
+ """
+ A simple section that links to articles, to test linking to related items
+ in admin views.
+ """
+ name = models.CharField(max_length=100)
+
+class Article(models.Model):
+ """
+ A simple article to test admin views. Test backwards compatibility.
+ """
+ content = models.TextField()
+ date = models.DateTimeField()
+ section = models.ForeignKey(Section)
+
+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(
+ request, extra_context={
+ 'extra_var': 'Hello!'
+ }
+ )
+
+class CustomArticle(models.Model):
+ content = models.TextField()
+ date = models.DateTimeField()
+
+class CustomArticleAdmin(admin.ModelAdmin):
+ """
+ Tests various hooks for using custom templates and contexts.
+ """
+ change_list_template = 'custom_admin/change_list.html'
+ 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(
+ request, extra_context={
+ 'extra_var': 'Hello!'
+ }
+ )
+
+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)
+admin.site.register(ModelWithStringPrimaryKey)
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
new file mode 100644
index 0000000000..ad50928aa9
--- /dev/null
+++ b/tests/regressiontests/admin_views/tests.py
@@ -0,0 +1,362 @@
+
+from django.test import TestCase
+from django.contrib.auth.models import User, Permission
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.admin.models import LogEntry
+from django.contrib.admin.sites import LOGIN_FORM_KEY, _encode_post_data
+from django.contrib.admin.util import quote
+from django.utils.html import escape
+
+# local test models
+from models import Article, CustomArticle, Section, ModelWithStringPrimaryKey
+
+def get_perm(Model, perm):
+ """Return the permission object, for the Model"""
+ ct = ContentType.objects.get_for_model(Model)
+ return Permission.objects.get(content_type=ct,codename=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.
+ # 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,
+ 'username': 'super',
+ 'password': 'secret'}
+ self.super_email_login = {'post_data': _encode_post_data({}),
+ LOGIN_FORM_KEY: 1,
+ 'username': 'super@example.com',
+ 'password': 'secret'}
+ self.super_email_bad_login = {'post_data': _encode_post_data({}),
+ LOGIN_FORM_KEY: 1,
+ 'username': 'super@example.com',
+ 'password': 'notsecret'}
+ self.adduser_login = {'post_data': _encode_post_data({}),
+ LOGIN_FORM_KEY: 1,
+ 'username': 'adduser',
+ 'password': 'secret'}
+ self.changeuser_login = {'post_data': _encode_post_data({}),
+ LOGIN_FORM_KEY: 1,
+ 'username': 'changeuser',
+ 'password': 'secret'}
+ self.deleteuser_login = {'post_data': _encode_post_data({}),
+ LOGIN_FORM_KEY: 1,
+ 'username': 'deleteuser',
+ 'password': 'secret'}
+ self.joepublic_login = {'post_data': _encode_post_data({}),
+ LOGIN_FORM_KEY: 1,
+ 'username': 'joepublic',
+ 'password': 'secret'}
+
+ def testTrailingSlashRequired(self):
+ """
+ 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'
+ )
+ self.assertRedirects(request,
+ '/test_admin/admin/admin_views/article/add/'
+ )
+
+ 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
+ a 200 status code.
+ """
+ # Super User
+ request = self.client.get('/test_admin/admin/')
+ self.failUnlessEqual(request.status_code, 200)
+ login = self.client.post('/test_admin/admin/', self.super_login)
+ self.assertRedirects(login, '/test_admin/admin/')
+ self.assertFalse(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)
+ login = self.client.post('/test_admin/admin/', self.super_email_login)
+ self.assertContains(login, "Your e-mail address is not your username")
+ # only correct passwords get a username hint
+ login = self.client.post('/test_admin/admin/', self.super_email_bad_login)
+ self.assertContains(login, "Usernames cannot contain the &#39;@&#39; character")
+ new_user = User(username='jondoe', password='secret', email='super@example.com')
+ new_user.save()
+ # 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 &#39;@&#39; character")
+
+ # Add User
+ request = self.client.get('/test_admin/admin/')
+ self.failUnlessEqual(request.status_code, 200)
+ login = self.client.post('/test_admin/admin/', self.adduser_login)
+ self.assertRedirects(login, '/test_admin/admin/')
+ self.assertFalse(login.context)
+ self.client.get('/test_admin/admin/logout/')
+
+ # Change User
+ request = self.client.get('/test_admin/admin/')
+ self.failUnlessEqual(request.status_code, 200)
+ login = self.client.post('/test_admin/admin/', self.changeuser_login)
+ self.assertRedirects(login, '/test_admin/admin/')
+ self.assertFalse(login.context)
+ self.client.get('/test_admin/admin/logout/')
+
+ # Delete User
+ request = self.client.get('/test_admin/admin/')
+ self.failUnlessEqual(request.status_code, 200)
+ login = self.client.post('/test_admin/admin/', self.deleteuser_login)
+ self.assertRedirects(login, '/test_admin/admin/')
+ self.assertFalse(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)
+ login = self.client.post('/test_admin/admin/', self.joepublic_login)
+ self.failUnlessEqual(login.status_code, 200)
+ # Login.context is a list of context dicts we just need to check the first one.
+ self.assert_(login.context[0].get('error_message'))
+
+ def testAddView(self):
+ """Test add view restricts access and actually adds items."""
+
+ add_dict = {'content': '<p>great article</p>',
+ '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)
+ request = self.client.get('/test_admin/admin/admin_views/article/add/')
+ self.failUnlessEqual(request.status_code, 403)
+ # Try POST just to make sure
+ post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict)
+ 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)
+ post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict)
+ 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)
+ post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict)
+ 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.')
+ self.super_login['post_data'] = _encode_post_data(add_dict)
+ post = self.client.post('/test_admin/admin/admin_views/article/add/', self.super_login)
+ self.assertRedirects(post, '/test_admin/admin/admin_views/article/')
+ self.failUnlessEqual(Article.objects.all().count(), 4)
+ self.client.get('/test_admin/admin/logout/')
+
+ def testChangeView(self):
+ """Change view should restrict access and allow users to edit items."""
+
+ change_dict = {'content': '<p>edited article</p>',
+ '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)
+ request = self.client.get('/test_admin/admin/admin_views/article/')
+ self.failUnlessEqual(request.status_code, 403)
+ request = self.client.get('/test_admin/admin/admin_views/article/1/')
+ self.failUnlessEqual(request.status_code, 403)
+ 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)
+ request = self.client.get('/test_admin/admin/admin_views/article/')
+ self.failUnlessEqual(request.status_code, 200)
+ request = self.client.get('/test_admin/admin/admin_views/article/1/')
+ self.failUnlessEqual(request.status_code, 200)
+ post = self.client.post('/test_admin/admin/admin_views/article/1/', change_dict)
+ self.assertRedirects(post, '/test_admin/admin/admin_views/article/')
+ self.failUnlessEqual(Article.objects.get(pk=1).content, '<p>edited article</p>')
+ self.client.get('/test_admin/admin/logout/')
+
+ 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': '<p>great article</p>',
+ 'date_0': '2008-03-18',
+ 'date_1': '10:54:39'
+ })
+ 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'
+ request = self.client.get('/test_admin/admin/')
+ self.assertTemplateUsed(request, 'custom_admin/login.html')
+ self.assert_('Hello from a custom login template' in request.content)
+ self.client.post('/test_admin/admin/', self.changeuser_login)
+ 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):
+ kwargs['extra_context'] = {'foo': '*bar*'}
+ return original_index(*args, **kwargs)
+ admin.site.index = index
+ 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
+ admin.site.index_template = None
+
+ 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)
+ request = self.client.get('/test_admin/admin/admin_views/article/1/delete/')
+ self.failUnlessEqual(request.status_code, 403)
+ post = self.client.post('/test_admin/admin/admin_views/article/1/delete/', delete_dict)
+ 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)
+ self.assertRedirects(post, '/test_admin/admin/')
+ self.failUnlessEqual(Article.objects.all().count(), 0)
+ self.client.get('/test_admin/admin/logout/')
+
+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 = """<tr class="row1"><th><a href="%s/">%s</a></th></tr>""" % (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 = """<a href="admin_views/modelwithstringprimarykey/%s/">%s</a>""" % (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))
+ should_contain = """<a href="../../%s/">%s</a>""" % (quote(self.pk), escape(self.pk))
+ self.assertContains(response, should_contain)
diff --git a/tests/regressiontests/admin_views/urls.py b/tests/regressiontests/admin_views/urls.py
new file mode 100644
index 0000000000..e556812a45
--- /dev/null
+++ b/tests/regressiontests/admin_views/urls.py
@@ -0,0 +1,7 @@
+from django.conf.urls.defaults import *
+from django.contrib import admin
+
+urlpatterns = patterns('',
+ (r'^admin/doc/', include('django.contrib.admindocs.urls')),
+ (r'^admin/(.*)', admin.site.root),
+)