tags:

views:

257

answers:

4

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!

+5  A: 

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.

Steef
very useful approach, ths
yjfuk
A: 

You can look into RowLevelPermissions branch. It hasn't been included even in 1.1 beta though, I guess it still needs some development.

Pyetras
That branch is completely, totally, 100% dead forever. It will never be resurrected, completed, updated, or integrated into mainline Django. Unfortunately, SVN doesn't have any way of saying "this branch is closed and will have no further work", so people keep tripping over it.
James Bennett
Oh. Well, they could mention something in the docs anyway.
Pyetras
+1  A: 

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.

James Bennett
A: 

How about posting h1 tags

sudhh