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:
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:
The user is allowed to review the flatpages “Events” and “Contact”.
And you can do this with any objects in any direction:
The user is allowed to review the flatpages “Events” and “Contact”. Another user is allowed to publish the flatpage “Events”.
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.
Please see Handling permissions using Django’s admin interface for this.
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!
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!"
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.
{% 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.