diff --git a/django/contrib/admin/util.py b/django/contrib/admin/util.py
index 61182a6..6e01bdc 100644
|
a
|
b
|
def get_deleted_objects(objs, opts, user, admin_site, using):
|
| 116 | 116 | None, (quote(obj._get_pk_val()),)) |
| 117 | 117 | p = '%s.%s' % (opts.app_label, |
| 118 | 118 | opts.get_delete_permission()) |
| 119 | | if not user.has_perm(p): |
| | 119 | if not user.has_perm(p, obj): |
| 120 | 120 | perms_needed.add(opts.verbose_name) |
| 121 | 121 | # Display a link to the admin page. |
| 122 | 122 | return mark_safe(u'%s: <a href="%s">%s</a>' % |
| … |
… |
def reverse_field_path(model, path):
|
| 361 | 361 | for piece in pieces: |
| 362 | 362 | field, model, direct, m2m = parent._meta.get_field_by_name(piece) |
| 363 | 363 | # skip trailing data field if extant: |
| 364 | | if len(reversed_path) == len(pieces)-1: # final iteration |
| | 364 | if len(reversed_path) == len(pieces) - 1: # final iteration |
| 365 | 365 | try: |
| 366 | 366 | get_model_from_relation(field) |
| 367 | 367 | except NotRelationField: |
diff --git a/tests/regressiontests/admin_util/models.py b/tests/regressiontests/admin_util/models.py
index 0e81df3..6253641 100644
|
a
|
b
|
|
| 1 | 1 | from django.db import models |
| | 2 | from django.contrib.auth.models import User |
| 2 | 3 | |
| 3 | 4 | |
| 4 | 5 | class Article(models.Model): |
| … |
… |
class Article(models.Model):
|
| 17 | 18 | return "nothing" |
| 18 | 19 | test_from_model_with_override.short_description = "not What you Expect" |
| 19 | 20 | |
| | 21 | |
| 20 | 22 | class Count(models.Model): |
| 21 | 23 | num = models.PositiveSmallIntegerField() |
| 22 | 24 | parent = models.ForeignKey('self', null=True) |
| … |
… |
class Count(models.Model):
|
| 24 | 26 | def __unicode__(self): |
| 25 | 27 | return unicode(self.num) |
| 26 | 28 | |
| | 29 | |
| 27 | 30 | class Event(models.Model): |
| 28 | 31 | date = models.DateTimeField(auto_now_add=True) |
| 29 | 32 | |
| | 33 | |
| 30 | 34 | class Location(models.Model): |
| 31 | 35 | event = models.OneToOneField(Event, verbose_name='awesome event') |
| 32 | 36 | |
| | 37 | |
| 33 | 38 | class Guest(models.Model): |
| 34 | 39 | event = models.OneToOneField(Event) |
| 35 | 40 | name = models.CharField(max_length=255) |
| 36 | 41 | |
| 37 | 42 | class Meta: |
| 38 | 43 | verbose_name = "awesome guest" |
| | 44 | |
| | 45 | |
| | 46 | class PrivilegedUser(User): |
| | 47 | special_usernames = ['special'] |
| | 48 | |
| | 49 | def has_perm(self, perm, obj=None): |
| | 50 | if obj and obj.username in self.special_usernames: |
| | 51 | return True |
| | 52 | return False |
diff --git a/tests/regressiontests/admin_util/tests.py b/tests/regressiontests/admin_util/tests.py
index 8113f2e..b1c9503 100644
|
a
|
b
|
from django.conf import settings
|
| 6 | 6 | from django.contrib import admin |
| 7 | 7 | from django.contrib.admin import helpers |
| 8 | 8 | from django.contrib.admin.util import (display_for_field, label_for_field, |
| 9 | | lookup_field, NestedObjects) |
| | 9 | lookup_field, NestedObjects, get_deleted_objects) |
| 10 | 10 | from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE |
| 11 | 11 | from django.contrib.sites.models import Site |
| | 12 | from django.contrib.auth.models import User |
| 12 | 13 | from django.db import models, DEFAULT_DB_ALIAS |
| 13 | 14 | from django import forms |
| 14 | 15 | from django.test import TestCase |
| 15 | | from django.utils import unittest |
| 16 | 16 | from django.utils.formats import localize |
| 17 | 17 | from django.utils.safestring import mark_safe |
| 18 | 18 | |
| 19 | | from .models import Article, Count, Event, Location |
| | 19 | from .models import Article, Count, Event, Location, PrivilegedUser |
| 20 | 20 | |
| 21 | 21 | |
| 22 | 22 | class NestedObjectsTests(TestCase): |
| … |
… |
class NestedObjectsTests(TestCase):
|
| 70 | 70 | # Should not require additional queries to populate the nested graph. |
| 71 | 71 | self.assertNumQueries(2, self._collect, 0) |
| 72 | 72 | |
| 73 | | class UtilTests(unittest.TestCase): |
| | 73 | class UtilTests(TestCase): |
| | 74 | urls = 'regressiontests.admin_util.urls' |
| | 75 | |
| 74 | 76 | def test_values_from_lookup_field(self): |
| 75 | 77 | """ |
| 76 | 78 | Regression test for #12654: lookup_field |
| … |
… |
class UtilTests(unittest.TestCase):
|
| 218 | 220 | ) |
| 219 | 221 | self.assertEqual( |
| 220 | 222 | label_for_field("test_from_model", Article, |
| 221 | | model_admin = MockModelAdmin, |
| 222 | | return_attr = True |
| | 223 | model_admin=MockModelAdmin, |
| | 224 | return_attr=True |
| 223 | 225 | ), |
| 224 | 226 | ("not Really the Model", MockModelAdmin.test_from_model) |
| 225 | 227 | ) |
| … |
… |
class UtilTests(unittest.TestCase):
|
| 266 | 268 | # safestring should not be escaped |
| 267 | 269 | class MyForm(forms.Form): |
| 268 | 270 | text = forms.CharField(label=mark_safe('<i>text</i>')) |
| 269 | | cb = forms.BooleanField(label=mark_safe('<i>cb</i>')) |
| | 271 | cb = forms.BooleanField(label=mark_safe('<i>cb</i>')) |
| 270 | 272 | |
| 271 | 273 | form = MyForm() |
| 272 | 274 | self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), |
| … |
… |
class UtilTests(unittest.TestCase):
|
| 277 | 279 | # normal strings needs to be escaped |
| 278 | 280 | class MyForm(forms.Form): |
| 279 | 281 | text = forms.CharField(label='&text') |
| 280 | | cb = forms.BooleanField(label='&cb') |
| | 282 | cb = forms.BooleanField(label='&cb') |
| 281 | 283 | |
| 282 | 284 | form = MyForm() |
| 283 | 285 | self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), |
| 284 | 286 | '<label for="id_text" class="required inline">&text:</label>') |
| 285 | 287 | self.assertEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(), |
| 286 | 288 | '<label for="id_cb" class="vCheckboxLabel required inline">&cb</label>') |
| | 289 | |
| | 290 | def test_get_deleted_objects_has_perm(self): |
| | 291 | |
| | 292 | class MockAdminSite: |
| | 293 | name = 'admin-ns' |
| | 294 | _registry = [User] |
| | 295 | |
| | 296 | privileged_user = PrivilegedUser() |
| | 297 | |
| | 298 | # privileged_user don't have permission to modify all users, |
| | 299 | # but have permission to user with username 'test' |
| | 300 | # get_deleted_objects have to pass object for privileges check |
| | 301 | obj = User(username='special') |
| | 302 | obj.save() |
| | 303 | (deleted_objects, perms_needed, protected) = get_deleted_objects( |
| | 304 | [obj], None, privileged_user, MockAdminSite(), None) |
| | 305 | self.assertFalse(obj._meta.verbose_name in perms_needed) |
| | 306 | |
| | 307 | obj = User(username='common') |
| | 308 | obj.save() |
| | 309 | (deleted_objects, perms_needed, protected) = get_deleted_objects( |
| | 310 | [obj], None, privileged_user, MockAdminSite(), None) |
| | 311 | self.assertTrue(obj._meta.verbose_name in perms_needed) |
diff --git a/tests/regressiontests/admin_util/urls.py b/tests/regressiontests/admin_util/urls.py
new file mode 100644
index 0000000..22f4717
|
-
|
+
|
|
| | 1 | from __future__ import absolute_import |
| | 2 | |
| | 3 | from django.conf.urls import patterns, url, include |
| | 4 | |
| | 5 | |
| | 6 | class URLObject(object): |
| | 7 | def __init__(self, app_name, namespace): |
| | 8 | self.app_name = app_name |
| | 9 | self.namespace = namespace |
| | 10 | |
| | 11 | def urls(self): |
| | 12 | return patterns('', |
| | 13 | url(r'^inner/(\d+)/$', 'empty_view', name='auth_user_change'), |
| | 14 | ), self.app_name, self.namespace |
| | 15 | urls = property(urls) |
| | 16 | |
| | 17 | testobj1 = URLObject('testapp', 'admin-ns') |
| | 18 | |
| | 19 | urlpatterns = patterns('regressiontests.admin_util.urls', |
| | 20 | (r'^test1/', include(testobj1.urls)), |
| | 21 | ) |