Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object Ownership in Django

Tags:

django

I'm wondering how I might accomplish a simple 'object ownership' system with django models, such that, by default, only the owner of an object may edit it.

I am attempting to allow a 'Management' group to edit all objects on behalf of the object owners, and have at this point added a custom permission:

class Meta:
    permissions     = (
        ("manage_object", "Can manage objects"),
    )

To establish 'ownership' I've toyed with the idea of adding a def to the model:

def owner(self):
    return self.user

But then, how might I go further? I could implement the permissions in a view and display relevant UI with a template, i.e.:

if request.user is object.owner:
    # ... do stuff
elseif request.user.has_perm.can_manage:  # this line is probably not right
    # ... do something else

... and then present different UI elements on a template level.

So, the question is:

  • what faults/benefits are there with this approach?
  • are there recommendations?
  • or, any other previously implement methods?

Best thanks!

like image 907
Antonius Common Avatar asked Jun 16 '09 00:06

Antonius Common


2 Answers

My approach would be adding a method to the model:

class YourModelWithOwnership(models.model):
    ...

    def user_can_manage_me(self, user):
        return user == self.user or user.has_perm('your_app.manage_object')

I'd then call that method whenever a permission check is required, and take some action based on the outcome. So for a view that would be

from django.shortcuts import get_object_or_404
...

def view_func(request, item_id):
    item = get_object_or_404(YourModelWithOwnership, id=item_id) # or whatever is needed to get the object
    if not item.user_can_manage_me(request.user):
        # user not allowed to manage
        ...
    else:
        ...

Later I'd probably realize that that's still quite some boilerplate code to write in every view that needs that test, so I'd implement an exception that's thrown when a user can't manage an object...

class CannotManage(Exception):
    pass

...and add another method to the model:

from django.db import models
from django.shortcuts import get_object_or_404

class YourModelWithOwnership(models.model):
    ...

    @classmethod
    def get_manageable_object_or_404(cls, user, *args, **kwds):
        item = get_object_or_404(cls, *args, **kwds)
        if not item.user_can_manage_me(user):
            raise CannotManage
        return item

Then, in the view functions, this can be used:

def view_func(request, item_id):
    item = YourModelWithOwnership.get_manageable_object_or_404(request.user, id=item_id)
    ...

This will of course raise an exception when the user isn't the owner and does not have the proper permission. That exception can be handled in the process_exception() method of a custom middleware class so that there's a single handler for all instances where a user is not allowed to mess with the object.

like image 156
Steef Avatar answered Nov 05 '22 23:11

Steef


A while back I wrote up the usual technique for doing this in the admin. You may want to read through that to see how the implementation works.

like image 40
James Bennett Avatar answered Nov 05 '22 21:11

James Bennett