/tests/regressiontests/admin_views/tests.py
Python | 2965 lines | 2815 code | 74 blank | 76 comment | 22 complexity | 5e7b4ee6ace0b61c905cd2fad1686963 MD5 | raw file
Possible License(s): BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- # coding: utf-8
- import re
- import datetime
- import urlparse
- from django.conf import settings
- from django.core import mail
- from django.core.exceptions import SuspiciousOperation
- from django.core.files import temp as tempfile
- from django.core.urlresolvers import reverse
- # Register auth models with the admin.
- from django.contrib.auth import REDIRECT_FIELD_NAME, admin
- from django.contrib.auth.models import User, Permission, UNUSABLE_PASSWORD
- from django.contrib.contenttypes.models import ContentType
- from django.contrib.admin.models import LogEntry, DELETION
- from django.contrib.admin.sites import LOGIN_FORM_KEY
- from django.contrib.admin.util import quote
- from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
- from django.contrib.admin.views.main import IS_POPUP_VAR
- from django.forms.util import ErrorList
- import django.template.context
- from django.test import TestCase
- from django.utils import formats
- from django.utils.cache import get_max_age
- from django.utils.encoding import iri_to_uri
- from django.utils.html import escape
- from django.utils.http import urlencode
- from django.utils.translation import activate, deactivate
- from django.utils import unittest
- # local test models
- from models import (Article, BarAccount, CustomArticle, EmptyModel,
- FooAccount, Gallery, ModelWithStringPrimaryKey,
- Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast,
- Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit,
- Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee,
- Question, Answer, Inquisition, Actor, FoodDelivery,
- RowLevelChangePermissionModel, Paper, CoverLetter, Story, OtherStory)
- class AdminViewBasicTest(TestCase):
- fixtures = ['admin-views-users.xml', 'admin-views-colors.xml',
- 'admin-views-fabrics.xml', 'admin-views-books.xml']
- # Store the bit of the URL where the admin is registered as a class
- # variable. That way we can test a second AdminSite just by subclassing
- # this test case and changing urlbit.
- urlbit = 'admin'
- def setUp(self):
- self.old_USE_I18N = settings.USE_I18N
- self.old_USE_L10N = settings.USE_L10N
- self.old_LANGUAGE_CODE = settings.LANGUAGE_CODE
- self.client.login(username='super', password='secret')
- settings.USE_I18N = True
- def tearDown(self):
- settings.USE_I18N = self.old_USE_I18N
- settings.USE_L10N = self.old_USE_L10N
- settings.LANGUAGE_CODE = self.old_LANGUAGE_CODE
- self.client.logout()
- formats.reset_format_cache()
- def testTrailingSlashRequired(self):
- """
- If you leave off the trailing slash, app should redirect and add it.
- """
- request = self.client.get('/test_admin/%s/admin_views/article/add' % self.urlbit)
- self.assertRedirects(request,
- '/test_admin/%s/admin_views/article/add/' % self.urlbit, status_code=301
- )
- def testBasicAddGet(self):
- """
- A smoke test to ensure GET on the add_view works.
- """
- response = self.client.get('/test_admin/%s/admin_views/section/add/' % self.urlbit)
- self.assertEqual(response.status_code, 200)
- def testAddWithGETArgs(self):
- response = self.client.get('/test_admin/%s/admin_views/section/add/' % self.urlbit, {'name': 'My Section'})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- 'value="My Section"' in response.content,
- "Couldn't find an input with the right value in the response."
- )
- def testBasicEditGet(self):
- """
- A smoke test to ensure GET on the change_view works.
- """
- response = self.client.get('/test_admin/%s/admin_views/section/1/' % self.urlbit)
- self.assertEqual(response.status_code, 200)
- def testBasicEditGetStringPK(self):
- """
- A smoke test to ensure GET on the change_view works (returns an HTTP
- 404 error, see #11191) when passing a string as the PK argument for a
- model with an integer PK field.
- """
- response = self.client.get('/test_admin/%s/admin_views/section/abc/' % self.urlbit)
- self.assertEqual(response.status_code, 404)
- def testBasicAddPost(self):
- """
- A smoke test to ensure POST on add_view works.
- """
- post_data = {
- "name": u"Another Section",
- # inline data
- "article_set-TOTAL_FORMS": u"3",
- "article_set-INITIAL_FORMS": u"0",
- "article_set-MAX_NUM_FORMS": u"0",
- }
- response = self.client.post('/test_admin/%s/admin_views/section/add/' % self.urlbit, post_data)
- self.assertEqual(response.status_code, 302) # redirect somewhere
- def testPopupAddPost(self):
- """
- Ensure http response from a popup is properly escaped.
- """
- post_data = {
- '_popup': u'1',
- 'title': u'title with a new\nline',
- 'content': u'some content',
- 'date_0': u'2010-09-10',
- 'date_1': u'14:55:39',
- }
- response = self.client.post('/test_admin/%s/admin_views/article/add/' % self.urlbit, post_data)
- self.failUnlessEqual(response.status_code, 200)
- self.assertContains(response, 'dismissAddAnotherPopup')
- self.assertContains(response, 'title with a new\u000Aline')
- # Post data for edit inline
- inline_post_data = {
- "name": u"Test section",
- # inline data
- "article_set-TOTAL_FORMS": u"6",
- "article_set-INITIAL_FORMS": u"3",
- "article_set-MAX_NUM_FORMS": u"0",
- "article_set-0-id": u"1",
- # there is no title in database, give one here or formset will fail.
- "article_set-0-title": u"Norske bostaver ćřĺ skaper problemer",
- "article_set-0-content": u"<p>Middle content</p>",
- "article_set-0-date_0": u"2008-03-18",
- "article_set-0-date_1": u"11:54:58",
- "article_set-0-section": u"1",
- "article_set-1-id": u"2",
- "article_set-1-title": u"Need a title.",
- "article_set-1-content": u"<p>Oldest content</p>",
- "article_set-1-date_0": u"2000-03-18",
- "article_set-1-date_1": u"11:54:58",
- "article_set-2-id": u"3",
- "article_set-2-title": u"Need a title.",
- "article_set-2-content": u"<p>Newest content</p>",
- "article_set-2-date_0": u"2009-03-18",
- "article_set-2-date_1": u"11:54:58",
- "article_set-3-id": u"",
- "article_set-3-title": u"",
- "article_set-3-content": u"",
- "article_set-3-date_0": u"",
- "article_set-3-date_1": u"",
- "article_set-4-id": u"",
- "article_set-4-title": u"",
- "article_set-4-content": u"",
- "article_set-4-date_0": u"",
- "article_set-4-date_1": u"",
- "article_set-5-id": u"",
- "article_set-5-title": u"",
- "article_set-5-content": u"",
- "article_set-5-date_0": u"",
- "article_set-5-date_1": u"",
- }
- def testBasicEditPost(self):
- """
- A smoke test to ensure POST on edit_view works.
- """
- response = self.client.post('/test_admin/%s/admin_views/section/1/' % self.urlbit, self.inline_post_data)
- self.assertEqual(response.status_code, 302) # redirect somewhere
- def testEditSaveAs(self):
- """
- Test "save as".
- """
- post_data = self.inline_post_data.copy()
- post_data.update({
- '_saveasnew': u'Save+as+new',
- "article_set-1-section": u"1",
- "article_set-2-section": u"1",
- "article_set-3-section": u"1",
- "article_set-4-section": u"1",
- "article_set-5-section": u"1",
- })
- response = self.client.post('/test_admin/%s/admin_views/section/1/' % self.urlbit, post_data)
- self.assertEqual(response.status_code, 302) # redirect somewhere
- def testChangeListSortingCallable(self):
- """
- Ensure we can sort on a list_display field that is a callable
- (column 2 is callable_year in ArticleAdmin)
- """
- response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'ot': 'asc', 'o': 2})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- response.content.index('Oldest content') < response.content.index('Middle content') and
- response.content.index('Middle content') < response.content.index('Newest content'),
- "Results of sorting on callable are out of order."
- )
- def testChangeListSortingModel(self):
- """
- Ensure we can sort on a list_display field that is a Model method
- (colunn 3 is 'model_year' in ArticleAdmin)
- """
- response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'ot': 'dsc', 'o': 3})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- response.content.index('Newest content') < response.content.index('Middle content') and
- response.content.index('Middle content') < response.content.index('Oldest content'),
- "Results of sorting on Model method are out of order."
- )
- def testChangeListSortingModelAdmin(self):
- """
- Ensure we can sort on a list_display field that is a ModelAdmin method
- (colunn 4 is 'modeladmin_year' in ArticleAdmin)
- """
- response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'ot': 'asc', 'o': 4})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- response.content.index('Oldest content') < response.content.index('Middle content') and
- response.content.index('Middle content') < response.content.index('Newest content'),
- "Results of sorting on ModelAdmin method are out of order."
- )
- def testLimitedFilter(self):
- """Ensure admin changelist filters do not contain objects excluded via limit_choices_to.
- This also tests relation-spanning filters (e.g. 'color__value').
- """
- response = self.client.get('/test_admin/%s/admin_views/thing/' % self.urlbit)
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- '<div id="changelist-filter">' in response.content,
- "Expected filter not found in changelist view."
- )
- self.assertFalse(
- '<a href="?color__id__exact=3">Blue</a>' in response.content,
- "Changelist filter not correctly limited by limit_choices_to."
- )
- def testRelationSpanningFilters(self):
- response = self.client.get('/test_admin/%s/admin_views/chapterxtra1/' %
- self.urlbit)
- self.assertEqual(response.status_code, 200)
- self.assertContains(response, '<div id="changelist-filter">')
- filters = {
- 'chap__id__exact': dict(
- values=[c.id for c in Chapter.objects.all()],
- test=lambda obj, value: obj.chap.id == value),
- 'chap__title': dict(
- values=[c.title for c in Chapter.objects.all()],
- test=lambda obj, value: obj.chap.title == value),
- 'chap__book__id__exact': dict(
- values=[b.id for b in Book.objects.all()],
- test=lambda obj, value: obj.chap.book.id == value),
- 'chap__book__name': dict(
- values=[b.name for b in Book.objects.all()],
- test=lambda obj, value: obj.chap.book.name == value),
- 'chap__book__promo__id__exact': dict(
- values=[p.id for p in Promo.objects.all()],
- test=lambda obj, value:
- obj.chap.book.promo_set.filter(id=value).exists()),
- 'chap__book__promo__name': dict(
- values=[p.name for p in Promo.objects.all()],
- test=lambda obj, value:
- obj.chap.book.promo_set.filter(name=value).exists()),
- }
- for filter_path, params in filters.items():
- for value in params['values']:
- query_string = urlencode({filter_path: value})
- # ensure filter link exists
- self.assertContains(response, '<a href="?%s">' % query_string)
- # ensure link works
- filtered_response = self.client.get(
- '/test_admin/%s/admin_views/chapterxtra1/?%s' % (
- self.urlbit, query_string))
- self.assertEqual(filtered_response.status_code, 200)
- # ensure changelist contains only valid objects
- for obj in filtered_response.context['cl'].query_set.all():
- self.assertTrue(params['test'](obj, value))
- def testIncorrectLookupParameters(self):
- """Ensure incorrect lookup parameters are handled gracefully."""
- response = self.client.get('/test_admin/%s/admin_views/thing/' % self.urlbit, {'notarealfield': '5'})
- self.assertRedirects(response, '/test_admin/%s/admin_views/thing/?e=1' % self.urlbit)
- response = self.client.get('/test_admin/%s/admin_views/thing/' % self.urlbit, {'color__id__exact': 'StringNotInteger!'})
- self.assertRedirects(response, '/test_admin/%s/admin_views/thing/?e=1' % self.urlbit)
- def testIsNullLookups(self):
- """Ensure is_null is handled correctly."""
- Article.objects.create(title="I Could Go Anywhere", content="Versatile", date=datetime.datetime.now())
- response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit)
- self.assertTrue('4 articles' in response.content, '"4 articles" missing from response')
- response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': 'false'})
- self.assertTrue('3 articles' in response.content, '"3 articles" missing from response')
- response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': 'true'})
- self.assertTrue('1 article' in response.content, '"1 article" missing from response')
- def testLogoutAndPasswordChangeURLs(self):
- response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit)
- self.assertFalse('<a href="/test_admin/%s/logout/">' % self.urlbit not in response.content)
- self.assertFalse('<a href="/test_admin/%s/password_change/">' % self.urlbit not in response.content)
- def testNamedGroupFieldChoicesChangeList(self):
- """
- Ensures the admin changelist shows correct values in the relevant column
- for rows corresponding to instances of a model in which a named group
- has been used in the choices option of a field.
- """
- response = self.client.get('/test_admin/%s/admin_views/fabric/' % self.urlbit)
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- '<a href="1/">Horizontal</a>' in response.content and
- '<a href="2/">Vertical</a>' in response.content,
- "Changelist table isn't showing the right human-readable values set by a model field 'choices' option named group."
- )
- def testNamedGroupFieldChoicesFilter(self):
- """
- Ensures the filter UI shows correctly when at least one named group has
- been used in the choices option of a model field.
- """
- response = self.client.get('/test_admin/%s/admin_views/fabric/' % self.urlbit)
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- '<div id="changelist-filter">' in response.content,
- "Expected filter not found in changelist view."
- )
- self.assertTrue(
- '<a href="?surface__exact=x">Horizontal</a>' in response.content and
- '<a href="?surface__exact=y">Vertical</a>' in response.content,
- "Changelist filter isn't showing options contained inside a model field 'choices' option named group."
- )
- def testChangeListNullBooleanDisplay(self):
- Post.objects.create(public=None)
- # This hard-codes the URl because it'll fail if it runs
- # against the 'admin2' custom admin (which doesn't have the
- # Post model).
- response = self.client.get("/test_admin/admin/admin_views/post/")
- self.assertTrue('icon-unknown.gif' in response.content)
- def testI18NLanguageNonEnglishDefault(self):
- """
- Check if the Javascript i18n view returns an empty language catalog
- if the default language is non-English but the selected language
- is English. See #13388 and #3594 for more details.
- """
- try:
- settings.LANGUAGE_CODE = 'fr'
- activate('en-us')
- response = self.client.get('/test_admin/admin/jsi18n/')
- self.assertNotContains(response, 'Choisir une heure')
- finally:
- deactivate()
- def testI18NLanguageNonEnglishFallback(self):
- """
- Makes sure that the fallback language is still working properly
- in cases where the selected language cannot be found.
- """
- try:
- settings.LANGUAGE_CODE = 'fr'
- activate('none')
- response = self.client.get('/test_admin/admin/jsi18n/')
- self.assertContains(response, 'Choisir une heure')
- finally:
- deactivate()
- def testL10NDeactivated(self):
- """
- Check if L10N is deactivated, the Javascript i18n view doesn't
- return localized date/time formats. Refs #14824.
- """
- try:
- settings.LANGUAGE_CODE = 'ru'
- settings.USE_L10N = False
- activate('ru')
- response = self.client.get('/test_admin/admin/jsi18n/')
- self.assertNotContains(response, '%d.%m.%Y %H:%M:%S')
- self.assertContains(response, '%Y-%m-%d %H:%M:%S')
- finally:
- deactivate()
- def test_disallowed_filtering(self):
- self.assertRaises(SuspiciousOperation,
- self.client.get, "/test_admin/admin/admin_views/album/?owner__email__startswith=fuzzy"
- )
- try:
- self.client.get("/test_admin/admin/admin_views/thing/?color__value__startswith=red")
- self.client.get("/test_admin/admin/admin_views/thing/?color__value=red")
- except SuspiciousOperation:
- self.fail("Filters are allowed if explicitly included in list_filter")
- try:
- self.client.get("/test_admin/admin/admin_views/person/?age__gt=30")
- except SuspiciousOperation:
- self.fail("Filters should be allowed if they involve a local field without the need to whitelist them in list_filter or date_hierarchy.")
- e1 = Employee.objects.create(name='Anonymous', gender=1, age=22, alive=True, code='123')
- e2 = Employee.objects.create(name='Visitor', gender=2, age=19, alive=True, code='124')
- WorkHour.objects.create(datum=datetime.datetime.now(), employee=e1)
- WorkHour.objects.create(datum=datetime.datetime.now(), employee=e2)
- response = self.client.get("/test_admin/admin/admin_views/workhour/")
- self.assertEqual(response.status_code, 200)
- self.assertContains(response, 'employee__person_ptr__exact')
- response = self.client.get("/test_admin/admin/admin_views/workhour/?employee__person_ptr__exact=%d" % e1.pk)
- self.assertEqual(response.status_code, 200)
- def test_allowed_filtering_15103(self):
- """
- Regressions test for ticket 15103 - filtering on fields defined in a
- ForeignKey 'limit_choices_to' should be allowed, otherwise raw_id_fields
- can break.
- """
- try:
- self.client.get("/test_admin/admin/admin_views/inquisition/?leader__name=Palin&leader__age=27")
- except SuspiciousOperation:
- self.fail("Filters should be allowed if they are defined on a ForeignKey pointing to this model")
- class AdminJavaScriptTest(AdminViewBasicTest):
- def testSingleWidgetFirsFieldFocus(self):
- """
- JavaScript-assisted auto-focus on first field.
- """
- response = self.client.get('/test_admin/%s/admin_views/picture/add/' % self.urlbit)
- self.assertContains(
- response,
- '<script type="text/javascript">document.getElementById("id_name").focus();</script>'
- )
- def testMultiWidgetFirsFieldFocus(self):
- """
- JavaScript-assisted auto-focus should work if a model/ModelAdmin setup
- is such that the first form field has a MultiWidget.
- """
- response = self.client.get('/test_admin/%s/admin_views/reservation/add/' % self.urlbit)
- self.assertContains(
- response,
- '<script type="text/javascript">document.getElementById("id_start_date_0").focus();</script>'
- )
- class SaveAsTests(TestCase):
- fixtures = ['admin-views-users.xml','admin-views-person.xml']
- def setUp(self):
- self.client.login(username='super', password='secret')
- def tearDown(self):
- self.client.logout()
- def test_save_as_duplication(self):
- """Ensure save as actually creates a new person"""
- post_data = {'_saveasnew':'', 'name':'John M', 'gender':1, 'age': 42}
- response = self.client.post('/test_admin/admin/admin_views/person/1/', post_data)
- self.assertEqual(len(Person.objects.filter(name='John M')), 1)
- self.assertEqual(len(Person.objects.filter(id=1)), 1)
- def test_save_as_display(self):
- """
- Ensure that 'save as' is displayed when activated and after submitting
- invalid data aside save_as_new will not show us a form to overwrite the
- initial model.
- """
- response = self.client.get('/test_admin/admin/admin_views/person/1/')
- self.assertTrue(response.context['save_as'])
- post_data = {'_saveasnew':'', 'name':'John M', 'gender':3, 'alive':'checked'}
- response = self.client.post('/test_admin/admin/admin_views/person/1/', post_data)
- self.assertEqual(response.context['form_url'], '../add/')
- class CustomModelAdminTest(AdminViewBasicTest):
- urlbit = "admin2"
- def testCustomAdminSiteLoginForm(self):
- self.client.logout()
- request = self.client.get('/test_admin/admin2/')
- self.assertEqual(request.status_code, 200)
- login = self.client.post('/test_admin/admin2/', {
- REDIRECT_FIELD_NAME: '/test_admin/admin2/',
- LOGIN_FORM_KEY: 1,
- 'username': 'customform',
- 'password': 'secret',
- })
- self.assertEqual(login.status_code, 200)
- self.assertContains(login, 'custom form error')
- def testCustomAdminSiteLoginTemplate(self):
- self.client.logout()
- request = self.client.get('/test_admin/admin2/')
- self.assertTemplateUsed(request, 'custom_admin/login.html')
- self.assertTrue('Hello from a custom login template' in request.content)
- def testCustomAdminSiteLogoutTemplate(self):
- request = self.client.get('/test_admin/admin2/logout/')
- self.assertTemplateUsed(request, 'custom_admin/logout.html')
- self.assertTrue('Hello from a custom logout template' in request.content)
- def testCustomAdminSiteIndexViewAndTemplate(self):
- request = self.client.get('/test_admin/admin2/')
- self.assertTemplateUsed(request, 'custom_admin/index.html')
- self.assertTrue('Hello from a custom index template *bar*' in request.content)
- def testCustomAdminSitePasswordChangeTemplate(self):
- request = self.client.get('/test_admin/admin2/password_change/')
- self.assertTemplateUsed(request, 'custom_admin/password_change_form.html')
- self.assertTrue('Hello from a custom password change form template' in request.content)
- def testCustomAdminSitePasswordChangeDoneTemplate(self):
- request = self.client.get('/test_admin/admin2/password_change/done/')
- self.assertTemplateUsed(request, 'custom_admin/password_change_done.html')
- self.assertTrue('Hello from a custom password change done template' in request.content)
- def testCustomAdminSiteView(self):
- self.client.login(username='super', password='secret')
- response = self.client.get('/test_admin/%s/my_view/' % self.urlbit)
- self.assertTrue(response.content == "Django is a magical pony!", response.content)
- 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 = {
- REDIRECT_FIELD_NAME: '/test_admin/admin/',
- LOGIN_FORM_KEY: 1,
- 'username': 'super',
- 'password': 'secret',
- }
- self.super_email_login = {
- REDIRECT_FIELD_NAME: '/test_admin/admin/',
- LOGIN_FORM_KEY: 1,
- 'username': 'super@example.com',
- 'password': 'secret',
- }
- self.super_email_bad_login = {
- REDIRECT_FIELD_NAME: '/test_admin/admin/',
- LOGIN_FORM_KEY: 1,
- 'username': 'super@example.com',
- 'password': 'notsecret',
- }
- self.adduser_login = {
- REDIRECT_FIELD_NAME: '/test_admin/admin/',
- LOGIN_FORM_KEY: 1,
- 'username': 'adduser',
- 'password': 'secret',
- }
- self.changeuser_login = {
- REDIRECT_FIELD_NAME: '/test_admin/admin/',
- LOGIN_FORM_KEY: 1,
- 'username': 'changeuser',
- 'password': 'secret',
- }
- self.deleteuser_login = {
- REDIRECT_FIELD_NAME: '/test_admin/admin/',
- LOGIN_FORM_KEY: 1,
- 'username': 'deleteuser',
- 'password': 'secret',
- }
- self.joepublic_login = {
- REDIRECT_FIELD_NAME: '/test_admin/admin/',
- LOGIN_FORM_KEY: 1,
- 'username': 'joepublic',
- 'password': 'secret',
- }
- self.no_username_login = {
- REDIRECT_FIELD_NAME: '/test_admin/admin/',
- LOGIN_FORM_KEY: 1,
- 'password': 'secret',
- }
- 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.assertEqual(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.assertEqual(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, "Please enter a correct username and password.")
- 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, "Please enter a correct username and password.")
- # Add User
- request = self.client.get('/test_admin/admin/')
- self.assertEqual(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.assertEqual(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.assertEqual(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.assertEqual(request.status_code, 200)
- login = self.client.post('/test_admin/admin/', self.joepublic_login)
- self.assertEqual(login.status_code, 200)
- self.assertContains(login, "Please enter a correct username and password.")
- # Requests without username should not return 500 errors.
- request = self.client.get('/test_admin/admin/')
- self.assertEqual(request.status_code, 200)
- login = self.client.post('/test_admin/admin/', self.no_username_login)
- self.assertEqual(login.status_code, 200)
- form = login.context[0].get('form')
- self.assertEqual(form.errors['username'][0], 'This field is required.')
- def testLoginSuccessfullyRedirectsToOriginalUrl(self):
- request = self.client.get('/test_admin/admin/')
- self.assertEqual(request.status_code, 200)
- query_string = 'the-answer=42'
- redirect_url = '/test_admin/admin/?%s' % query_string
- new_next = {REDIRECT_FIELD_NAME: redirect_url}
- login = self.client.post('/test_admin/admin/', dict(self.super_login, **new_next), QUERY_STRING=query_string)
- self.assertRedirects(login, redirect_url)
- def testAddView(self):
- """Test add view restricts access and actually adds items."""
- add_dict = {'title' : 'Dřm ikke',
- '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)
- # make sure the view removes test cookie
- self.assertEqual(self.client.session.test_cookie_worked(), False)
- request = self.client.get('/test_admin/admin/admin_views/article/add/')
- self.assertEqual(request.status_code, 403)
- # Try POST just to make sure
- post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict)
- self.assertEqual(post.status_code, 403)
- self.assertEqual(Article.objects.all().count(), 3)
- 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)
- addpage = self.client.get('/test_admin/admin/admin_views/article/add/')
- self.assertEqual(addpage.status_code, 200)
- change_list_link = '<a href="../">Articles</a> ›'
- self.assertFalse(change_list_link in addpage.content,
- 'User restricted to add permission is given link to change list view in breadcrumbs.')
- post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict)
- self.assertRedirects(post, '/test_admin/admin/')
- self.assertEqual(Article.objects.all().count(), 4)
- self.assertEqual(len(mail.outbox), 1)
- self.assertEqual(mail.outbox[0].subject, 'Greetings from a created object')
- 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)
- addpage = self.client.get('/test_admin/admin/admin_views/article/add/')
- self.assertEqual(addpage.status_code, 200)
- self.assertFalse(change_list_link not in addpage.content,
- 'Unrestricted user is not given link to change list view in breadcrumbs.')
- post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict)
- self.assertRedirects(post, '/test_admin/admin/admin_views/article/')
- self.assertEqual(Article.objects.all().count(), 5)
- self.client.get('/test_admin/admin/logout/')
- # 8509 - if a normal user is already logged in, it is possible
- # to change user into the superuser without error
- login = self.client.login(username='joepublic', password='secret')
- # Check and make sure that if user expires, data still persists
- self.client.get('/test_admin/admin/')
- self.client.post('/test_admin/admin/', self.super_login)
- # make sure the view removes test cookie
- self.assertEqual(self.client.session.test_cookie_worked(), False)
- def testChangeView(self):
- """Change view should restrict access and allow users to edit items."""
- change_dict = {'title' : 'Ikke fordřmt',
- '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.assertEqual(request.status_code, 403)
- request = self.client.get('/test_admin/admin/admin_views/article/1/')
- self.assertEqual(request.status_code, 403)
- post = self.client.post('/test_admin/admin/admin_views/article/1/', change_dict)
- self.assertEqual(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.assertEqual(request.status_code, 200)
- request = self.client.get('/test_admin/admin/admin_views/article/1/')
- self.assertEqual(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.assertEqual(Article.objects.get(pk=1).content, '<p>edited article</p>')
- # one error in form should produce singular error message, multiple errors plural
- change_dict['title'] = ''
- post = self.client.post('/test_admin/admin/admin_views/article/1/', change_dict)
- self.assertEqual(request.status_code, 200)
- self.assertTrue('Please correct the error below.' in post.content,
- 'Singular error message not found in response to post with one error.')
- change_dict['content'] = ''
- post = self.client.post('/test_admin/admin/admin_views/article/1/', change_dict)
- self.assertEqual(request.status_code, 200)
- self.assertTrue('Please correct the errors below.' in post.content,
- 'Plural error message not found in response to post with multiple errors.')
- self.client.get('/test_admin/admin/logout/')
- # Test redirection when using row-level change permissions. Refs #11513.
- RowLevelChangePermissionModel.objects.create(id=1, name="odd id")
- RowLevelChangePermissionModel.objects.create(id=2, name="even id")
- for login_dict in [self.super_login, self.changeuser_login, self.adduser_login, self.deleteuser_login]:
- self.client.post('/test_admin/admin/', login_dict)
- request = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/')
- self.assertEqual(request.status_code, 403)
- request = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/', {'name': 'changed'})
- self.assertEqual(RowLevelChangePermissionModel.objects.get(id=1).name, 'odd id')
- self.assertEqual(request.status_code, 403)
- request = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/')
- self.assertEqual(request.status_code, 200)
- request = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/', {'name': 'changed'})
- self.assertEqual(RowLevelChangePermissionModel.objects.get(id=2).name, 'changed')
- self.assertRedirects(request, '/test_admin/admin/')
- self.client.get('/test_admin/admin/logout/')
- for login_dict in [self.joepublic_login, self.no_username_login]:
- self.client.post('/test_admin/admin/', login_dict)
- request = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/')
- self.assertEqual(request.status_code, 200)
- self.assertContains(request, 'login-form')
- request = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/', {'name': 'changed'})
- self.assertEqual(RowLevelChangePermissionModel.objects.get(id=1).name, 'odd id')
- self.assertEqual(request.status_code, 200)
- self.assertContains(request, 'login-form')
- request = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/')
- self.assertEqual(request.status_code, 200)
- self.assertContains(request, 'login-form')
- request = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/', {'name': 'changed again'})
- self.assertEqual(RowLevelChangePermissionModel.objects.get(id=2).name, 'changed')
- self.assertEqual(request.status_code, 200)
- self.assertContains(request, 'login-form')
- self.client.get('/test_admin/admin/logout/')
- def testConditionallyShowAddSectionLink(self):
- """
- The foreign key widget should only show the "add related" button if the
- user has permission to add that related item.
- """
- # Set up and log in user.
- url = '/test_admin/admin/admin_views/article/add/'
- add_link_text = ' class="add-another"'
- self.client.get('/test_admin/admin/')
- self.client.post('/test_admin/admin/', self.adduser_login)
- # The add user can't add sections yet, so they shouldn't see the "add
- # section" link.
- response = self.client.get(url)
- self.assertNotContains(response, add_link_text)
- # Allow the add user to add sections too. Now they can see the "add
- # section" link.
- add_user = User.objects.get(username='adduser')
- perm = get_perm(Section, Section._meta.get_add_permission())
- add_user.user_permissions.add(perm)
- response = self.client.get(url)
- self.assertContains(response, add_link_text)
- 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.assertEqual(request.status_code, 200)
- self.assertTrue("var hello = 'Hello!';" in request.content)
- self.assertTemplateUsed(request, 'custom_admin/change_list.html')
- # Test custom add form template
- request = self.client.get('/test_admin/admin/admin_views/customarticle/add/')
- self.assertTemplateUsed(request, 'custom_admin/add_form.html')
- # Add an article so we can test delete, change, 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.assertEqual(CustomArticle.objects.all().count(), 1)
- article_pk = CustomArticle.objects.all()[0].pk
- # Test custom delete, change, and object history templates
- # Test custom change form template
- request = self.client.get('/test_admin/admin/admin_views/customarticle/%d/' % article_pk)
- self.assertTemplateUsed(request, 'custom_admin/change_form.html')
- request = self.client.get('/test_admin/admin/admin_views/customarticle/%d/delete/' % article_pk)
- self.assertTemplateUsed(request, 'custom_admin/delete_confirmation.html')
- request = self.client.post('/test_admin/admin/admin_views/customarticle/', data={
- 'index': 0,
- 'action': ['delete_selected'],
- '_selected_action': ['1'],
- })
- self.assertTemplateUsed(request, 'custom_admin/delete_selected_confirmation.html')
- request = self.client.get('/test_admin/admin/admin_views/customarticle/%d/history/' % article_pk)
- self.assertTemplateUsed(request, 'custom_admin/object_history.html')
- self.client.get('/test_admin/admin/logout/')
- 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.assertEqual(request.status_code, 403)
- post = self.client.post('/test_admin/admin/admin_views/article/1/delete/', delete_dict)
- self.assertEqual(post.status_code, 403)
- self.assertEqual(Article.objects.all().count(), 3)
- 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.assertEqual(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.assertEqual(Article.objects.all().count(), 2)
- self.assertEqual(len(mail.outbox), 1)
- self.assertEqual(mail.outbox[0].subject, 'Greetings from a deleted object')
- article_ct = ContentType.objects.get_for_model(Article)
- logged = LogEntry.objects.get(content_type=article_ct, action_flag=DELETION)
- self.assertEqual(logged.object_id, u'1')
- self.client.get('/test_admin/admin/logout/')
- def testDisabledPermissionsWhenLoggedIn(self):
- self.client.login(username='super', password='secret')
- superuser = User.objects.get(username='super')
- superuser.is_active = False
- superuser.save()
- response = self.client.get('/test_admin/admin/')
- self.assertContains(response, 'id="login-form"')
- self.assertNotContains(response, 'Log out')
- response = self.client.get('/test_admin/admin/secure-view/')
- self.assertContains(response, 'id="login-form"')
- class AdminViewDeletedObjectsTest(TestCase):
- fixtures = ['admin-views-users.xml', 'deleted-objects.xml']
- def setUp(self):
- self.client.login(username='super', password='secret')
- def tearDown(self):
- self.client.logout()
- def test_nesting(self):
- """
- Objects should be nested to display the relationships that
- cause them to be scheduled for deletion.
- """
- pattern = re.compile(r"""<li>Plot: <a href=".+/admin_views/plot/1/">World Domination</a>\s*<ul>\s*<li>Plot details: <a href=".+/admin_views/plotdetails/1/">almost finished</a>""")
- response = self.client.get('/test_admin/admin/admin_views/villain/%s/delete/' % quote(1))
- self.assertTrue(pattern.search(response.content))
- def test_cyclic(self):
- """
- Cyclic relationships should still cause each object to only be
- listed once.
- """
- one = """<li>Cyclic one: <a href="/test_admin/admin/admin_views/cyclicone/1/">I am recursive</a>"""
- two = """<li>Cyclic two: <a href="/test_admin/admin/admin_views/cyclictwo/1/">I am recursive too</a>"""
- response = self.client.get('/test_admin/admin/admin_views/cyclicone/%s/delete/' % quote(1))
- self.assertContains(response, one, 1)
- self.assertContains(response, two, 1)
- def test_perms_needed(self):
- self.client.logout()
- delete_user = User.objects.get(username='deleteuser')
- delete_user.user_permissions.add(get_perm(Plot,
- Plot._meta.get_delete_permission()))
- self.assertTrue(self.client.login(username='deleteuser',
- password='secret'))
- response = self.client.get('/test_admin/admin/admin_views/plot/%s/delete/' % quote(1))
- self.assertContains(response, "your account doesn't have permission to delete the following types of objects")
- self.assertContains(response, "<li>plot details</li>")
- def test_protected(self):
- q = Question.objects.create(question="Why?")
- a1 = Answer.objects.create(question=q, answer="Because.")
- a2 = Answer.objects.create(question=q, answer="Yes.")
- response = self.client.get("/test_admin/admin/admin_views/question/%s/delete/" % quote(q.pk))
- self.assertContains(response, "would require deleting the following protected related objects")
- self.assertContains(response, '<li>Answer: <a href="/test_admin/admin/admin_views/answer/%s/">Because.</a></li>' % a1.pk)
- self.assertContains(response, '<li>Answer: <a href="/test_admin/admin/admin_views/answer/%s/">Yes.</a></li>' % a2.pk)
- def test_not_registered(self):
- should_contain = """<li>Secret hideout: underground bunker"""
- response = self.client.get('/test_admin/admin/admin_views/villain/%s/delete/' % quote(1))
- self.assertContains(response, should_contain, 1)
- def test_multiple_fkeys_to_same_model(self):
- """
- If a deleted object has two relationships from another model,
- both of those should be followed in looking for related
- objects to delete.
- """
- should_contain = """<li>Plot: <a href="/test_admin/admin/admin_views/plot/1/">World Domination</a>"""
- response = self.client.get('/test_admin/admin/admin_views/villain/%s/delete/' % quote(1))
- self.assertContains(response, should_contain)
- response = self.client.get('/test_admin/admin/admin_views/villain/%s/delete/' % quote(2))
- self.assertContains(response, should_contain)
- def test_multiple_fkeys_to_same_instance(self):
- """
- If a deleted object has two relationships pointing to it from
- another object, the other object should still only be listed
- once.
- """
- should_contain = """<li>Plot: <a href="/test_admin/admin/admin_views/plot/2/">World Peace</a></li>"""
- response = self.client.get('/test_admin/admin/admin_views/villain/%s/delete/' % quote(2))
- self.assertContains(response, should_contain, 1)
- def test_inheritance(self):
- """
- In the case of an inherited model, if either the child or
- parent-model instance is deleted, both instances are listed
- for deletion, as well as any relationships they have.
- """
- should_contain = [
- """<li>Villain: <a href="/test_admin/admin/admin_views/villain/3/">Bob</a>""",
- """<li>Super villain: <a href="/test_admin/admin/admin_views/supervillain/3/">Bob</a>""",
- """<li>Secret hideout: floating castle""",
- """<li>Super secret hideout: super floating castle!"""
- ]
- response = self.client.get('/test_admin/admin/admin_views/villain/%s/delete/' % quote(3))
- for should in should_contain:
- self.a…
Large files files are truncated, but you can click here to view the full file