Create a per-object permission

django-authority provides a super simple but nifty feature called per-object permission. A description would be:

Attach a <codename> to an object
Attach a <codename> to an user

If the user has <codename> and the object has <codename> then do-something,
otherwise do-something-else.

This might sound strange but let’s have a closer look on this pattern. In terms of users and flatpages a visual example would be:

../_images/authority-object-1to1.png

The user is allowed to review the flatpage “Events”.

You are not limited to a 1:1 relation, you can add this codename to multiple objects:

../_images/authority-object-1toN.png

The user is allowed to review the flatpages “Events” and “Contact”.

And you can do this with any objects in any direction:

../_images/authority-object-NtoN.png

The user is allowed to review the flatpages “Events” and “Contact”. Another user is allowed to publish the flatpage “Events”.

Create per-object permissions

Creating per-object permissions is super simple. See this piece of permission class code:

class FlatPagePermission(BasePermission):
    label = 'flatpage_permission'
    checks = ('review',)

authority.register(FlatPage, FlatPagePermission)

This permission class is similar to the one we already created in Create a basic permission but we added the line:

checks = ('review',)

This tells the permission class that it has a permission check (or codename) review. Under the hood this check gets translated to review_flatpage (review_<modelname>).

Important

Be sure that you have understand that we have not written any line of code yet. We just added the codename to the checks attribute.

Attach per-object permissions to objects

Please see Handling permissions using Django’s admin interface for this.

Check per-object permissions

As we noted above, we have not written any permission comparing code yet. This is your work. In theory the permission lookup for per-object permissions is:

if <theuser> has <codename> and <object> has <codename>:
    return True
else:
    return False

Important

The syntax is similiar to the permission checks we’ve already seen in Create a basic permission for the basic permissions but now we have to pass each function a model instance we want to check!

In your python code

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

Using the view decorator

from django.contrib.auth import Flatpage
from authority.decorators import permission_required_or_403

@permission_required_or_403('flatpage_permission.review_flatpage',
                            (Flatpage, 'url__iexact', 'url')) # The flatpage_object
def my_view(request, url):
    # ...

See Check permissions using the decorator how the decorator works in detail.

In your templates

{% ifhasperm "flatpage_permission.review_flatpage" request.user flatpage_object %}
    Yay, you can change *this* flatpage!
{% else %}
    Nope, sorry. You aren't allowed to change *this* flatpage.
{% endifhasperm %}

See Check permissions in templates how the template tag works in detail.