Permissions to Django Admin Actions
Asked Answered
W

5

8

I have written some custom actions for my django project, however cannot work out how to make them available to only superusers. I have tried putting an if statement round the actions line with Users.is_superuser but it keeps giving me an error saying there is no attribute called is_superuser.

Here is my admin.py file:

from django.contrib import admin
from models import Art, Agent, UserProfile
from django.contrib import admin
from django.contrib.auth.models import Group, User, AbstractUser
from django.contrib.auth import *
from import_export import resources
from import_export.admin import ImportExportModelAdmin

#admin.site.unregister(Group)

def approve_art(modeladmin, request, queryset):
    queryset.update(authenticate = "approved")

def reject_art(modeladmin, request, queryset):
    queryset.update(authenticate = "rejected")

# Add in this class to customized the Admin Interface
class ArtAdmin(ImportExportModelAdmin):
    list_display = ['id', 'identification', 'name', 'artist', 'category', 'type', 'agent', 'authenticate', ]
    search_fields = ('name', 'category', 'artist', 'id', 'authenticate', )

    actions = [approve_art, reject_art]
    list_filter = ["authenticate"]




class AgentAdmin(admin.ModelAdmin):
    list_display = ['id', 'name', 'phone', 'postcode', ]
    search_fields = ('name', 'id', )

class ArtResource(resources.ModelResource):

    class Meta:
        model = Art

# Update the registeration to include this customised interface
admin.site.register(Art, ArtAdmin)
admin.site.register(Agent, AgentAdmin)
Whippet answered 12/7, 2016 at 13:15 Comment(2)
Please include the code where you added an if statement.Madelle
I took out the line when I was trying different things but it was in the ArtAdmin class just before actions and all it was was if User.is_superuser:Whippet
H
14

You can customize the list of actions by overriding get_actions(). For example:

class ArtAdmin(ImportExportModelAdmin):
        list_display = ['id', 'identification', 'name', 'artist', 'category', 'type', 'agent', 'authenticate', ]
        search_fields = ('name', 'category', 'artist', 'id', 'authenticate', )
        list_filter = ["authenticate"]
        actions = [approve_art, reject_art]
   
        def get_actions(self, request):
            actions = super(ArtAdmin, self).get_actions(request)
            if not request.user.is_superuser:
               del actions[approve_art]
               del actions[reject_art]
            return actions

Check out https://docs.djangoproject.com/en/dev/ref/contrib/admin/actions/#conditionally-enabling-or-disabling-actions for more info

Handful answered 12/7, 2016 at 13:27 Comment(2)
You need to call parent classes get_actions method first I guess like this: actions = super(MyModelAdmin, self).get_actions(request) and return them in order to keep other actions though.Rodin
Yeah noticed that just after I posted, its been updated nowHandful
C
6

Update for Django >= 2.1

https://docs.djangoproject.com/en/2.2/ref/contrib/admin/actions/#setting-permissions-for-actions

in a nutshell:

def make_published(modeladmin, request, queryset):
    queryset.update(status='p')
make_published.allowed_permissions = ('change',)

or custom:

from django.contrib import admin
from django.contrib.auth import get_permission_codename

class ArticleAdmin(admin.ModelAdmin):
    actions = ['make_published']

    def make_published(self, request, queryset):
        queryset.update(status='p')
    make_published.allowed_permissions = ('publish',)

    def has_publish_permission(self, request):
        """Does the user have the publish permission?"""
        opts = self.opts
        codename = get_permission_codename('publish', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))

(Example code all taken from the linked documentation.)

Cher answered 26/6, 2019 at 16:9 Comment(0)
W
1

Considering that an action is not ModelAdmin-dependant, the best way to prevent it from being run by an non-authorized user remains to check it inside the action:

from django.core.exceptions import PermissionDenied

def approve_art(modeladmin, request, queryset):
    if not request.user.is_superuser:
        raise PermissionDenied
    queryset.update(authenticate = "approved")

Which is how django handles it for the delete_selected action.

The action would still remain available on the dropdown list though, but will return a 403 HTTP code.

Waterfowl answered 12/7, 2016 at 15:35 Comment(0)
R
0

You can override your ModelAdmin's get_actions method like this:

def get_actions(self, request):
    actions = super(MyModelAdmin, self).get_actions(request)
    if request.user.is_superuser:
            actions.update(dict(youraction=youraction))
    return actions

Here the documentation materials you may want to look at.

Rodin answered 12/7, 2016 at 13:26 Comment(0)
M
0

Only for superusers, you can display approve_art and reject_art admin actions by overriding get_actions() as shown below:

class ArtAdmin(ImportExportModelAdmin):

    # ...

    actions = ["approve_art", "reject_art"]

    def get_actions(self, request):
        actions = super().get_actions(request)
        if not request.user.is_superuser:
            del actions["approve_art"]
            del actions["reject_art"]
        return actions
Mutter answered 1/1, 2023 at 17:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.