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 no particular order, you should define only one of them):

  • 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.1.tar.gz (22.6 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.1-py3-none-any.whl (8.0 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for django_policies-0.1.tar.gz
Algorithm Hash digest
SHA256 a02dcfca18b092e9a52aec853b740dd0dd7dd7ecff55bdb5275c3c99f1f56795
MD5 d64946acd143360acaf00c6df9367d11
BLAKE2b-256 41a618ebd42ac061703278b09c7cca51572d9db26e2cc182d40a6896012dd434

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for django_policies-0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 aaa42f1bc61681fe6abaae5f7c1d6ace36dacd841277723ae390989fbca6700d
MD5 512c555b55bab0663df80902e9dd8059
BLAKE2b-256 ce8d077684bc1e8498b1ad91e09e966ea6a714cd5ac43b1979576c0173bfab48

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