38

I've found 3 row-level permission solutions for Django 1.2+

Could someone tell if there is any recommended more than the others, what are their main differences, etc.?

Tadeck
  • 132,510
  • 28
  • 152
  • 198
Akasha
  • 2,162
  • 1
  • 29
  • 47
  • i was reading about django extensions and found out they do custom permissions as well? im confused, do they? which is the default go-to for permissions on django nowadays? https://django-extensions.readthedocs.io/en/latest/command_signals.html#custom-permissions-for-all-models – Mr-Programs Jan 26 '19 at 15:13

2 Answers2

26

I'll start this by saying we use none of these for object level permission - we use our own custom method and I really wish we hadn't. If you can avoid object level permissions at all, do so, they are a pain to organise.

This is how I evaluate the 3 apps you've mentioned.

Active Development:

  1. django-guardian (1 week ago)
  2. django-object-permissions (1 year ago)
  3. django-authority (nearly 2 years ago)

API

  1. django-guardian (save an instance of a defined model)
  2. django-object-permissions (register permissions)
  3. django-authority (define classes)

The above are in order by the way.

I'd recommend guardian purely on API alone, but the fact that it is still being developed where the others aren't usually means a big win.

Josh Smeaton
  • 47,939
  • 24
  • 129
  • 164
21

As for Aug '13, django-object-permissions has been superseded by django-permission. The 3 projects are on active development.

Personally, I prefer authority or permission, which uses methods for checking permissions (runtime), rather than django-guardian which uses database to keep the permissions (attached upon object creation, f.e.).

-- EDIT --

Examples from the docs.

django-guardian

joe = User.objects.create(username='joe')
task = Task.objects.create(summary='Some job', content='', reported_by=boss)
joe.has_perm('view_task', task)
>> False
assign_perm('view_task', joe, task)
joe.has_perm('view_task', task)
>> True

You assign the permission and keep it in database.

django-authority

Declaration:

class FlatpagePermission(permissions.BasePermission):
    label = 'flatpage_permission'
    checks = ('morning_flatpage_check',)

    def morning_flatpage_check(self, flatpage):
        hour = int(datetime.datetime.now().strftime("%H"))
        if hour >= 8 and hour <= 12 and flatpage.url == '/about/':
            return True
        return False

authority.register(Flatpage, FlatpagePermission)

Usage:

def my_view(request):
    check = FlatPagePermission(request.user)
    flatpage_object = Flatpage.objects.get(url='/homepage/')
    if check.morning_flatpage_check(flatpage=flatpage_object):
        print "Yay, you can change *this* flatpage!"

It also wraps standard django permissions, but you can see the flexibility in the above custom permission which -AFAIK- you cannot do in guardian.

Common Usecase

A Student can belong to Classroom(s).

guardian:

  1. When Student is assigned to new Classroom, attach permission 'attend_classroom' to Student over Classroom object.
  2. When Student is removed from Classroom, remove 'attend_classroom' permission to Student over Classroom object.
  3. When accessing Classroom, check 'attend_classroom' permission.

authority:

  1. Define custom permission ClassroomPermission.can_attend_classroom(), which will query if Student belongs to Classroom.
  2. When accessing Classroom, check ClassroomPermission.can_attend_classroom()

Authority keeps the checking logic in a separate file. Guardian needs attach/detaching permissions though the rest of the code.

laffuste
  • 16,287
  • 8
  • 84
  • 91
  • I don't really understand what you mean by runtime vs object creation. Presumably they both use the database to store permissions, and they both use an API to retrieve them. – Rob Grant Aug 21 '14 at 10:34
  • @RobertGrant: I added a couple of examples for clarity. – laffuste Aug 22 '14 at 04:05
  • Okay, I think you're saying that the way Authority works is you define a custom method for each combination of object type and permission type, where you write the code to check if someone has a permission, whereas in Guardian you say `user.has_perm('classroom.attend_classroom')`? – Rob Grant Aug 22 '14 at 07:25
  • Do the recommendations here remain true today? [Authority](https://github.com/jezdez/django-authority) looks pretty close to what I want, class-based security voters, but no activity for over a year… are there any alternatives? – Steve Apr 02 '15 at 13:45
  • 1
    [django-permission](https://github.com/lambdalisue/django-permission) looks pretty good, I think I am going to give that a go over authority, and see if I can just ignore the db permissions and use the custom class-based stuff – Steve Apr 02 '15 at 14:09
  • I migrated from guardian to authority because, in my case, it was error prone to maintain it. It's easier for new devs to understand a protected view than to persist permissions in service classes (logic is spread). Please contribute to this Question with your findings if they apply :) – laffuste Apr 02 '15 at 14:23
  • Would you mind updating the answer now that we have django 4 / 2022? – Martin Thoma Jan 31 '22 at 22:53
  • sorry @Martin Thoma, it's been years i haven't used django and i am out of the loop currently – laffuste Feb 07 '22 at 07:21
  • No problem, I just thought I give it a shot! Thank you for coming back – Martin Thoma Feb 07 '22 at 12:04