Reputation: 398
I have two admin models, one is called Animal and another one is called Person. Each one has its own has_delete_permission
on the ModelAdmin
class.
The code I am using is listed below.
class Animal(models.Model):
sound = models.CharField(max_length=25, blank=True, null=True)
class Person(models.Model):
sound = models.CharField(max_length=25, blank=True, null=True)
class AnimalAdmin(admin.ModelAdmin):
model = Animal
def has_delete_permission(self, request, obj=None):
if request.POST and request.POST.get('action') == 'delete_selected':
animals = Animal.objects.filter( id__in = request.POST.getlist('_selected_action') )
print (animals)
return True
class PersonAdmin(admin.ModelAdmin):
model = Person
def has_delete_permission(self, request, obj=None):
return True
admin.site.register(Animal, AnimalAdmin)
admin.site.register(Person, PersonAdmin)
When I try to delete a Person instance that have the same ID of some Animals, the instances of Animals are printed. This could be a serious problem if I was doing some logic like changing the database or showing a message to the user.
The point is why has_delete_permission
methods of different classes are also executed ?
Upvotes: 2
Views: 934
Reputation: 13327
This happens because of one method of the class AdminSite
: each_context
.
def each_context(self, request):
"""
Return a dictionary of variables to put in the template context for
*every* page in the admin site.
For sites running on a subpath, use the SCRIPT_NAME value if site_url
hasn't been customized.
"""
This method is called in every pages rendered in the admin backend, and it calls successively get_app_list(request)
then _build_app_dict(request)
, which is looping over all admin models to check get_model_perms(request)
:
def get_model_perms(self, request):
"""
Return a dict of all perms for this model. This dict has the keys
``add``, ``change``, ``delete``, and ``view`` mapping to the True/False
for each of those actions.
"""
return {
'add': self.has_add_permission(request),
'change': self.has_change_permission(request),
'delete': self.has_delete_permission(request),
'view': self.has_view_permission(request),
}
So if you override has_delete_permission
in others ModelAdmin
, it will be called too, each time you display a page.
You are seeing the instances of Animals
matching the same indexes of the deleted Person
because you filter the queryset with a simple list of indexes coming from request
(request.POST.getlist('_selected_action')
).
Note : nothing is printed when you are not in a POST request.
That said, you should avoid mixing different things in one function : has_delete_permission
is about checking a delete permission on a model. I'm not sure what you want to check/prevent here, but you may find a better place.
Upvotes: 2