Alan
Alan

Reputation: 398

DjangoAdmin has_delete_permission executed from another Admin Class

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

Answers (1)

PRMoureu
PRMoureu

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

Related Questions