Skip to main content

No project description provided

Project description

Django Policies

Policy-based Django permissions backend

Django Policies is a flexible, code-based permissions backend for Django, inspired by Laravel's policies. Instead of managing object-level permissions via the database, Django Policies lets you define rules using simple Python methods, making your authorization logic easier to test, maintain, and reason about.

@register(Article)
class ArticlePolicy(Policy):
  def can_change(self, user, article):
    if user.is_staff:
      return True
 
    return user == article.author

Installation

pip install django-policies

Add django_policies to INSTALLED_APPS and add backend to AUTHENTICATION_BACKENDS:

# settings.py snippet
INSTALLED_APPS = [
    ...
    "django_policies",
]

AUTHENTICATION_BACKENDS = [
    "django_policies.backends.PolicyBackend",
    "django.contrib.auth.backends.ModelBackend",
]

Register your first policy in policies.py in your application. Django Policies will automatically discover policies.

from django_policies.decorators import register
from django_policies.policies import Policy
...

@register(Article)
class ArticlePolicy(Policy):
    def can_change(self, user, obj):
        return user == obj.author

Usage

Permission mapping

When a policy is registered, all permission checks for that model will be handled by the registered policy. By default, 4 permissions are registered for the model (add_<model>, change_<model>, delete_<model>, view_<model>) and more can be added using permissions in the model's meta.

For every permission, two methods on the policy class are considered (in this order, first that is found will be called):

  • full permission name: can_change_article
  • last part of the permission name dropped: can_change

Permissions that are not defined in the policy will not be handled by Policies, but can still be handled by other authentication backends.

Permission checks without object

Sometimes, you may need to check if a user has permission without an object instance. For example when you don't have an instance available (creating a new one), or when you want to know if a user has a permission in general.

When a permission check is initiated without an object instance, Django Policies will consult can_<perm>_some(user) method instead of can_<perm>(user, object):

class ArticlePolicy(Policy):
    def can_change(self, user, object):
        # Called when an object instance is provided.
        ...

    def can_change_some(self, user):
        # Called when an object instance is not provided.
        ...

The _some prefix can be configured using no_object_suffix property on the policy class.

Constant policies

Sometimes, you want to set policy to a constant value:

class ArticlePolicy(Policy):
    def can_change(self, user, obj):
        return False

You can also set can_change to a constant boolean value:

class ArticlePolicy(Policy):
    can_change = False

Handling anonymous users

By default, your policies will get called for AnonymousUser, so you will need to handle their permissions as well.

def can_change(self, user, obj):
    if not user.is_authenticated:
        return False

    ...

Handling anonymous users in every method can lead to repetitive code. To simplify this, you can globally deny access for anonymous users in a policy by setting deny_anonymous:

class ArticlePolicy(Policy):
    deny_anonymous = True

The above is equivalent to inserting if not user.is_authenticated: return False to all policy methods.

For some applications, you will find that denying anoymous access should be the default. Django Policies allows you to change the project default in Django settings:

POLICIES_DENY_ANONYMOUS_DEFAULT = True

Checking permissions

Inside views, you can use the default Django's has_perm on the user object:

user.has_perm("app.change_article", article) # -> calls can_change

user.has_perm("app.change_article") # -> calls can_change_some

In template code, Django does not provide a way to access object permissions, so a custom template tag is provided:

{% load policies %}

{% has_perm user "app.change_article" article as can_change %}
{% if can_change %}...{% endif %}

{% has_perm user "app.change_article" as can_change %}
{% if can_change %}...{% endif %}
which is the same as {% if perms.app.change_article %}...{% endif %}

For generic views, a modified PermissionRequiredMixin is provided:

from django_policies.mixins import PermissionRequiredMixin

class MyView(PermissionRequiredMixin, ...):
    permission_required = "app.change_article"

    def get_permission_object(self):
        return self.article

Automatic discovery

Django Policies automatically discovers policies.py files in all installed apps. This behavior can be disabled by changing the POLICIES_AUTODISCOVER setting to False. Alternatively, a different file can be discovered by changing POLICIES_AUTODISCOVER_MODULE to another module name.

Other packages

  • django-rules, a different take on object permissions based on combining logic predicates
  • django-guardian, also a different take storing object permissions in a database

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_policies-0.3.tar.gz (24.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_policies-0.3-py3-none-any.whl (8.1 kB view details)

Uploaded Python 3

File details

Details for the file django_policies-0.3.tar.gz.

File metadata

  • Download URL: django_policies-0.3.tar.gz
  • Upload date:
  • Size: 24.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.0

File hashes

Hashes for django_policies-0.3.tar.gz
Algorithm Hash digest
SHA256 a041a5b28e692cbf9f056d7ac04e9793401dec42ae8f8940fac8e9fac0adbc9b
MD5 d663347b7f6fd7967f237dc1fd853faa
BLAKE2b-256 a6eb78964a119cc98358e84982729c5d0c0745c1e48b115c6f7fa980fb1fff76

See more details on using hashes here.

File details

Details for the file django_policies-0.3-py3-none-any.whl.

File metadata

File hashes

Hashes for django_policies-0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 8fddb2a89018d1c81a81b7c37c2ca54b83d01561527736c887ce31d6b3cb2d42
MD5 a51edd6b68f6fa63e9fc6bfe3790923b
BLAKE2b-256 2130bdc343f3d0d9780a5cd50a999045deae88a53f9a1c8db6fa272bf77f8012

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page