mirror of
https://github.com/django/django.git
synced 2025-03-06 07:22:32 +00:00
Fixed #28517 -- Fixed admin delete confirmation view crash when related models don't have a delete permission.
This commit is contained in:
parent
5d5a2bd299
commit
d1286a8a68
@ -149,8 +149,8 @@ def get_deleted_objects(objs, opts, user, admin_site, using):
|
|||||||
# Change url doesn't exist -- don't display link to edit
|
# Change url doesn't exist -- don't display link to edit
|
||||||
return no_edit_link
|
return no_edit_link
|
||||||
|
|
||||||
p = '%s.%s' % (opts.app_label,
|
if 'delete' in opts.default_permissions:
|
||||||
get_permission_codename('delete', opts))
|
p = '%s.%s' % (opts.app_label, get_permission_codename('delete', opts))
|
||||||
if not user.has_perm(p):
|
if not user.has_perm(p):
|
||||||
perms_needed.add(opts.verbose_name)
|
perms_needed.add(opts.verbose_name)
|
||||||
# Display a link to the admin page.
|
# Display a link to the admin page.
|
||||||
|
@ -36,11 +36,11 @@ from .models import (
|
|||||||
Person, Persona, Picture, Pizza, Plot, PlotDetails, PlotProxy,
|
Person, Persona, Picture, Pizza, Plot, PlotDetails, PlotProxy,
|
||||||
PluggableSearchPerson, Podcast, Post, PrePopulatedPost,
|
PluggableSearchPerson, Podcast, Post, PrePopulatedPost,
|
||||||
PrePopulatedPostLargeSlug, PrePopulatedSubPost, Promo, Question,
|
PrePopulatedPostLargeSlug, PrePopulatedSubPost, Promo, Question,
|
||||||
ReadablePizza, Recipe, Recommendation, Recommender, ReferencedByGenRel,
|
ReadablePizza, ReadOnlyPizza, Recipe, Recommendation, Recommender,
|
||||||
ReferencedByInline, ReferencedByParent, RelatedPrepopulated,
|
ReferencedByGenRel, ReferencedByInline, ReferencedByParent,
|
||||||
RelatedWithUUIDPKModel, Report, Reservation, Restaurant,
|
RelatedPrepopulated, RelatedWithUUIDPKModel, Report, Reservation,
|
||||||
RowLevelChangePermissionModel, Section, ShortMessage, Simple, Sketch,
|
Restaurant, RowLevelChangePermissionModel, Section, ShortMessage, Simple,
|
||||||
State, Story, StumpJoke, Subscriber, SuperVillain, Telegram, Thing,
|
Sketch, State, Story, StumpJoke, Subscriber, SuperVillain, Telegram, Thing,
|
||||||
Topping, UnchangeableObject, UndeletableObject, UnorderedObject,
|
Topping, UnchangeableObject, UndeletableObject, UnorderedObject,
|
||||||
UserMessenger, Villain, Vodcast, Whatsit, Widget, Worker, WorkHour,
|
UserMessenger, Villain, Vodcast, Whatsit, Widget, Worker, WorkHour,
|
||||||
)
|
)
|
||||||
@ -502,6 +502,19 @@ class StudentAdmin(admin.ModelAdmin):
|
|||||||
search_fields = ('name',)
|
search_fields = ('name',)
|
||||||
|
|
||||||
|
|
||||||
|
class ReadOnlyPizzaAdmin(admin.ModelAdmin):
|
||||||
|
readonly_fields = ('name', 'toppings')
|
||||||
|
|
||||||
|
def has_add_permission(self, request):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def has_change_permission(self, request, obj=None):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def has_delete_permission(self, request, obj=None):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class WorkHourAdmin(admin.ModelAdmin):
|
class WorkHourAdmin(admin.ModelAdmin):
|
||||||
list_display = ('datum', 'employee')
|
list_display = ('datum', 'employee')
|
||||||
list_filter = ('employee',)
|
list_filter = ('employee',)
|
||||||
@ -1001,6 +1014,7 @@ site.register(Book, inlines=[ChapterInline])
|
|||||||
site.register(Promo)
|
site.register(Promo)
|
||||||
site.register(ChapterXtra1, ChapterXtra1Admin)
|
site.register(ChapterXtra1, ChapterXtra1Admin)
|
||||||
site.register(Pizza, PizzaAdmin)
|
site.register(Pizza, PizzaAdmin)
|
||||||
|
site.register(ReadOnlyPizza, ReadOnlyPizzaAdmin)
|
||||||
site.register(ReadablePizza)
|
site.register(ReadablePizza)
|
||||||
site.register(Topping, ToppingAdmin)
|
site.register(Topping, ToppingAdmin)
|
||||||
site.register(Album, AlbumAdmin)
|
site.register(Album, AlbumAdmin)
|
||||||
|
@ -582,6 +582,14 @@ class ReadablePizza(Pizza):
|
|||||||
proxy = True
|
proxy = True
|
||||||
|
|
||||||
|
|
||||||
|
# No default permissions are created for this model and both name and toppings
|
||||||
|
# are readonly for this model's admin.
|
||||||
|
class ReadOnlyPizza(Pizza):
|
||||||
|
class Meta:
|
||||||
|
proxy = True
|
||||||
|
default_permissions = ()
|
||||||
|
|
||||||
|
|
||||||
class Album(models.Model):
|
class Album(models.Model):
|
||||||
owner = models.ForeignKey(User, models.SET_NULL, null=True, blank=True)
|
owner = models.ForeignKey(User, models.SET_NULL, null=True, blank=True)
|
||||||
title = models.CharField(max_length=30)
|
title = models.CharField(max_length=30)
|
||||||
|
@ -48,9 +48,9 @@ from .models import (
|
|||||||
MainPrepopulated, Media, ModelWithStringPrimaryKey, OtherStory, Paper,
|
MainPrepopulated, Media, ModelWithStringPrimaryKey, OtherStory, Paper,
|
||||||
Parent, ParentWithDependentChildren, ParentWithUUIDPK, Person, Persona,
|
Parent, ParentWithDependentChildren, ParentWithUUIDPK, Person, Persona,
|
||||||
Picture, Pizza, Plot, PlotDetails, PluggableSearchPerson, Podcast, Post,
|
Picture, Pizza, Plot, PlotDetails, PluggableSearchPerson, Podcast, Post,
|
||||||
PrePopulatedPost, Promo, Question, ReadablePizza, Recommendation,
|
PrePopulatedPost, Promo, Question, ReadablePizza, ReadOnlyPizza,
|
||||||
Recommender, RelatedPrepopulated, RelatedWithUUIDPKModel, Report,
|
Recommendation, Recommender, RelatedPrepopulated, RelatedWithUUIDPKModel,
|
||||||
Restaurant, RowLevelChangePermissionModel, SecretHideout, Section,
|
Report, Restaurant, RowLevelChangePermissionModel, SecretHideout, Section,
|
||||||
ShortMessage, Simple, State, Story, SuperSecretHideout, SuperVillain,
|
ShortMessage, Simple, State, Story, SuperSecretHideout, SuperVillain,
|
||||||
Telegram, TitleTranslation, Topping, UnchangeableObject, UndeletableObject,
|
Telegram, TitleTranslation, Topping, UnchangeableObject, UndeletableObject,
|
||||||
UnorderedObject, Villain, Vodcast, Whatsit, Widget, Worker, WorkHour,
|
UnorderedObject, Villain, Vodcast, Whatsit, Widget, Worker, WorkHour,
|
||||||
@ -1820,6 +1820,23 @@ class AdminViewPermissionsTest(TestCase):
|
|||||||
logged = LogEntry.objects.get(content_type=article_ct, action_flag=DELETION)
|
logged = LogEntry.objects.get(content_type=article_ct, action_flag=DELETION)
|
||||||
self.assertEqual(logged.object_id, str(self.a1.pk))
|
self.assertEqual(logged.object_id, str(self.a1.pk))
|
||||||
|
|
||||||
|
def test_delete_view_with_no_default_permissions(self):
|
||||||
|
"""
|
||||||
|
The delete view allows users to delete collected objects without a
|
||||||
|
'delete' permission (ReadOnlyPizza.Meta.default_permissions is empty).
|
||||||
|
"""
|
||||||
|
pizza = ReadOnlyPizza.objects.create(name='Double Cheese')
|
||||||
|
delete_url = reverse('admin:admin_views_readonlypizza_delete', args=(pizza.pk,))
|
||||||
|
self.client.force_login(self.adduser)
|
||||||
|
response = self.client.get(delete_url)
|
||||||
|
self.assertContains(response, 'admin_views/readonlypizza/%s/' % pizza.pk)
|
||||||
|
self.assertContains(response, '<h2>Summary</h2>')
|
||||||
|
self.assertContains(response, '<li>Read only pizzas: 1</li>')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
post = self.client.post(delete_url, {'post': 'yes'})
|
||||||
|
self.assertRedirects(post, reverse('admin:admin_views_readonlypizza_changelist'))
|
||||||
|
self.assertEqual(ReadOnlyPizza.objects.count(), 0)
|
||||||
|
|
||||||
def test_delete_view_nonexistent_obj(self):
|
def test_delete_view_nonexistent_obj(self):
|
||||||
self.client.force_login(self.deleteuser)
|
self.client.force_login(self.deleteuser)
|
||||||
url = reverse('admin:admin_views_article_delete', args=('nonexistent',))
|
url = reverse('admin:admin_views_article_delete', args=('nonexistent',))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user