drf-rules


Namedrf-rules JSON
Version 0.0.6 PyPI version JSON
download
home_pageNone
SummaryRules Permissions with Django DRF
upload_time2024-11-08 05:01:08
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseBSD-3-Clause
keywords django drf permissions rules
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            drf-rules
=========

.. image:: https://img.shields.io/pypi/v/drf-rules.svg
    :target: https://pypi.org/project/drf-rules
    :alt: PyPI - Version

.. image:: https://img.shields.io/pypi/pyversions/drf-rules.svg
    :target: https://pypi.org/project/drf-rules
    :alt: PyPI - Python Version

.. image:: https://coveralls.io/repos/github/lsaavedr/drf-rules/badge.svg
    :target: https://coveralls.io/github/lsaavedr/drf-rules
    :alt: Coverage Status

``drf-rules`` is a Django Rest Framework library that provides object-level
permissions based on rules. It allows you to define fine-grained access
control for your API endpoints, enabling you to specify which users or groups
can perform certain actions on specific objects.

----

.. _django-rules: https://github.com/dfunckt/django-rules


Features
--------

- **KISS Principle**: The library follows the KISS principle, providing a
  simple and easy-to-understand how it works.
- **Documented**: The library is well-documented, with clear examples and
  explanations of how to use its features.
- **Tested**: The library is thoroughly tested, with a high test coverage to
  ensure its reliability and correctness.
- **DRF Integration**: Seamlessly integrates with Django Rest Framework to
  provide object-level permissions.
- **Based on django-rules**: Built on top of the `django-rules`_ library,
  which provides a flexible and extensible rule system.


Table of Contents
-----------------

- `Requirements`_
- `Installation`_
- `Configuring Django`_
- `Defining Rules`_
- `Using Rules with DRF`_

  + `Permissions in models`_
  + `Permissions in views`_
- `License`_


Requirements
------------

``drf-rules`` requires Python 3.8 or newer and Django 3.2 or newer.

Note: At any given moment in time, `drf-rules` will maintain support for all
currently supported Django versions, while dropping support for those versions
that reached end-of-life in minor releases. See the Supported Versions section
on Django Project website for the current state and timeline.


Installation
------------

Using pip:

.. code-block:: console

    $ pip install drf-rules

Run test with:

.. code-block:: console

    $ ./runtests.sh


.. _`Configuring Django`:

Configuring Django (see `django-rules`_)
----------------------------------------

Add ``rules`` to ``INSTALLED_APPS``:

.. code-block:: python

    INSTALLED_APPS = (
        # ...
        'rules',
    )

Add the authentication backend:

.. code-block:: python

    AUTHENTICATION_BACKENDS = (
        'rules.permissions.ObjectPermissionBackend',
        'django.contrib.auth.backends.ModelBackend',
    )


.. _`Defining Rules`:

Defining Rules (see `django-rules`_)
------------------------------------

For a comprehensive guide on using `django-rules`_, please refer to the
detailed documentation.

We will suppose that you have a ``Book`` model and you want to restrict access
to it based on the user's group.

First, define the rule in a ``rules.py`` file:


.. code-block:: python

    import rules

    # Define a rule that checks if the user's group is 'librarians'
    @rules.predicate
    def is_librarian(user):
        return user.groups.filter(name='librarians').exists()

    # Define a rule that checks if the user's group is 'authors'
    @rules.predicate
    def is_author(user):
        return user.groups.filter(name='authors').exists()

    # Define a rule that checks if the user's group is 'managers'
    @rules.predicate
    def is_manager(user):
        return user.groups.filter(name='managers').exists()

    # Define a rule that checks if the user is the author of the book
    @rules.predicate
    def is_book_author(user, book):
        return book.author == user


.. _`Using Rules with DRF`:

Using Rules with DRF (see `django-rules`_)
------------------------------------------

We will assume that you have already defined all the necessary rules to
restrict access to your API.

The ``rules`` library is capable of providing object-level permissions in
Django. It includes an authorization backend and several template tags for use
in your templates. You will need to utilize this library to implement all the
required rules.


Permissions in models
+++++++++++++++++++++

It is common to have a set of permissions for a model, similar to what Django
provides with its default model permissions (such as *add*, *change*, etc.).
When using ``rules`` as the permission checking backend, you can declare
object-level permissions for any model in a similar manner, using a new
``Meta`` option.

To integrate the rules library with your Django models, you'll need to switch
your model's base class and metaclass to the extended versions provided in
``rules.contrib.models``. The extensions are lightweight and only augment the
models by registering permissions. They do not create any migrations for your
models.

The approach you take depends on whether you're using a custom base class
and/or metaclass for your models. Here are the steps:

* If you're using the stock ``django.db.models.Model`` as base for your models,
  simply switch over to ``RulesModel`` and you're good to go.
* If you're currently using the default ``django.db.models.Model`` as the base
  for your models, simply switch to using ``RulesModel`` instead, and you're
  all set.
* If you already have a custom base class that adds common functionality to
  your models, you can integrate ``RulesModelMixin`` and set ``RulesModelBase``
  as the metaclass. Here's how you can do it:

    .. code-block:: python

        from django.db.models import Model
        from rules.contrib.models import RulesModelBase, RulesModelMixin

        class MyModel(RulesModelMixin, Model, metaclass=RulesModelBase):
            ...

* If you're using a custom metaclass for your models, you'll know how to
  ensure it inherits from ``RulesModelBaseMixin``.

  To create your models, assuming you are using ``RulesModel`` as the base
  class directly, follow this example:

    .. code-block:: python

        import rules
        from rules.contrib.models import RulesModel

        class Book(RulesModel):
            class Meta:
                rules_permissions = {
                    "create": rules.is_staff,
                    "retrieve": rules.is_authenticated,
                }

  The ``RulesModelMixin`` includes methods that you can override to customize
  how a model's permissions are registered. For more details, refer to the
  `django-rules <https://github.com/dfunckt/django-rules>`_ documentation.


**NOTE:** The keys of ``rules_permissions`` differ from Django's default name
conventions (which are also used by ``django-rules``). Instead, we adopt the
Django Rest Framework (DRF) conventions. Below is a table showing the default
CRUD keys for both conventions:

.. list-table:: CRUD key Conventions
   :header-rows: 1

   * - action
     - django-rules
     - drf-rules
   * - Create
     - add
     - create
   * - Retrieve
     - view
     - retrieve
   * - Update
     - change
     - update/partial_update
   * - Delete
     - delete
     - destroy
   * - List
     - view
     - list

As demonstrated, the keys in `drf-rules` can distinguish directly between
various types of update actions, such as `update` and `partial_update`.
Additionally, they can differentiate between `list` and `retrieve` actions.
This is because `drf-rules` is designed to align with Django Rest Framework
(DRF) conventions, enabling it to operate seamlessly with DRF actions.

Another advantage of using this approach is that it facilitates an automatic
association between rules and Django Rest Framework (DRF) actions. As we will
see later, this allows for the seamless integration of `drf-rules` as
permissions in views.


Permissions in views
++++++++++++++++++++

This marks the first instance where we utilize ``drf-rules``. You can
configure the ``permission_classes`` attribute for a view or viewset by using
the ``ModelViewSet`` class-based views:

.. code-block:: python

  from rest_framework.decorators import action
  from rest_framework.viewsets import ModelViewSet

  from drf_rules.permissions import AutoRulesPermission


  class BookViewSet(ModelViewSet):
      queryset = Book.objects.all()
      serializer_class = BookSerializer
      permission_classes = [AutoRulesPermission]

      @action(detail=False)
      def custom_nodetail(self, request):
          return Response({'status': 'request was permitted'})

This defines permissions based on ``rules_permissions`` specified in the model.
To set permissions for custom actions, you can modify ``rules_permissions``.
For example, you can do this:


.. code-block:: python

  import rules
  from rules.contrib.models import RulesModel

  class Book(RulesModel):
      class Meta:
          rules_permissions = {
              "create": rules.is_staff,
              "retrieve": rules.is_authenticated,
              "custom_nodetail": rules.is_authenticated,
          }

With this configuration, the ``custom_nodetail`` action will be allowed only
to authenticated users. Note that the ``list``, ``update``, ``partial_update``
and ``destroy`` actions are not explicitly defined. Therefore, the
``:default:`` rule will be applied. However, since the ``:default:`` rule is
not defined, these actions will not be allowed at all. The ``:default:`` rule
is applicable only to conventional actions, such as ``list``, ``retrieve``,
``create``, ``update``, ``partial_update``, and ``destroy``. To ensure that
the ``:default:`` rule applies to all conventional actions that are not
explicitly defined, you can define it accordingly:

.. code-block:: python

  import rules
  from rules.contrib.models import RulesModel

  class Book(RulesModel):
      class Meta:
          rules_permissions = {
              "create": rules.is_staff,
              "retrieve": rules.is_authenticated,
              ":default:": rules.is_authenticated,
          }

In this case, if ``custom_nodetail`` rule is not explicitly defined,
``custom_nodetail`` action will not be allowed, even if the ``:default:`` is
specified. This is because ``custom_nodetail`` is not a conventional action.
However, the ``:default:`` rule will apply to the ``list``, ``update``,
``partial_update``, and ``destroy`` actions.


License
-------

``drf-rules`` is distributed under the terms of the
`BSD-3-Clause <https://spdx.org/licenses/BSD-3-Clause.html>`_ license.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "drf-rules",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "django, drf, permissions, rules",
    "author": null,
    "author_email": "Luis Saavedra <luis94855510@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/1e/4e/733f646a4573f87fe67487e2ae2d2cb206ee46f03229acc4f4215755affe/drf_rules-0.0.6.tar.gz",
    "platform": null,
    "description": "drf-rules\n=========\n\n.. image:: https://img.shields.io/pypi/v/drf-rules.svg\n    :target: https://pypi.org/project/drf-rules\n    :alt: PyPI - Version\n\n.. image:: https://img.shields.io/pypi/pyversions/drf-rules.svg\n    :target: https://pypi.org/project/drf-rules\n    :alt: PyPI - Python Version\n\n.. image:: https://coveralls.io/repos/github/lsaavedr/drf-rules/badge.svg\n    :target: https://coveralls.io/github/lsaavedr/drf-rules\n    :alt: Coverage Status\n\n``drf-rules`` is a Django Rest Framework library that provides object-level\npermissions based on rules. It allows you to define fine-grained access\ncontrol for your API endpoints, enabling you to specify which users or groups\ncan perform certain actions on specific objects.\n\n----\n\n.. _django-rules: https://github.com/dfunckt/django-rules\n\n\nFeatures\n--------\n\n- **KISS Principle**: The library follows the KISS principle, providing a\n  simple and easy-to-understand how it works.\n- **Documented**: The library is well-documented, with clear examples and\n  explanations of how to use its features.\n- **Tested**: The library is thoroughly tested, with a high test coverage to\n  ensure its reliability and correctness.\n- **DRF Integration**: Seamlessly integrates with Django Rest Framework to\n  provide object-level permissions.\n- **Based on django-rules**: Built on top of the `django-rules`_ library,\n  which provides a flexible and extensible rule system.\n\n\nTable of Contents\n-----------------\n\n- `Requirements`_\n- `Installation`_\n- `Configuring Django`_\n- `Defining Rules`_\n- `Using Rules with DRF`_\n\n  + `Permissions in models`_\n  + `Permissions in views`_\n- `License`_\n\n\nRequirements\n------------\n\n``drf-rules`` requires Python 3.8 or newer and Django 3.2 or newer.\n\nNote: At any given moment in time, `drf-rules` will maintain support for all\ncurrently supported Django versions, while dropping support for those versions\nthat reached end-of-life in minor releases. See the Supported Versions section\non Django Project website for the current state and timeline.\n\n\nInstallation\n------------\n\nUsing pip:\n\n.. code-block:: console\n\n    $ pip install drf-rules\n\nRun test with:\n\n.. code-block:: console\n\n    $ ./runtests.sh\n\n\n.. _`Configuring Django`:\n\nConfiguring Django (see `django-rules`_)\n----------------------------------------\n\nAdd ``rules`` to ``INSTALLED_APPS``:\n\n.. code-block:: python\n\n    INSTALLED_APPS = (\n        # ...\n        'rules',\n    )\n\nAdd the authentication backend:\n\n.. code-block:: python\n\n    AUTHENTICATION_BACKENDS = (\n        'rules.permissions.ObjectPermissionBackend',\n        'django.contrib.auth.backends.ModelBackend',\n    )\n\n\n.. _`Defining Rules`:\n\nDefining Rules (see `django-rules`_)\n------------------------------------\n\nFor a comprehensive guide on using `django-rules`_, please refer to the\ndetailed documentation.\n\nWe will suppose that you have a ``Book`` model and you want to restrict access\nto it based on the user's group.\n\nFirst, define the rule in a ``rules.py`` file:\n\n\n.. code-block:: python\n\n    import rules\n\n    # Define a rule that checks if the user's group is 'librarians'\n    @rules.predicate\n    def is_librarian(user):\n        return user.groups.filter(name='librarians').exists()\n\n    # Define a rule that checks if the user's group is 'authors'\n    @rules.predicate\n    def is_author(user):\n        return user.groups.filter(name='authors').exists()\n\n    # Define a rule that checks if the user's group is 'managers'\n    @rules.predicate\n    def is_manager(user):\n        return user.groups.filter(name='managers').exists()\n\n    # Define a rule that checks if the user is the author of the book\n    @rules.predicate\n    def is_book_author(user, book):\n        return book.author == user\n\n\n.. _`Using Rules with DRF`:\n\nUsing Rules with DRF (see `django-rules`_)\n------------------------------------------\n\nWe will assume that you have already defined all the necessary rules to\nrestrict access to your API.\n\nThe ``rules`` library is capable of providing object-level permissions in\nDjango. It includes an authorization backend and several template tags for use\nin your templates. You will need to utilize this library to implement all the\nrequired rules.\n\n\nPermissions in models\n+++++++++++++++++++++\n\nIt is common to have a set of permissions for a model, similar to what Django\nprovides with its default model permissions (such as *add*, *change*, etc.).\nWhen using ``rules`` as the permission checking backend, you can declare\nobject-level permissions for any model in a similar manner, using a new\n``Meta`` option.\n\nTo integrate the rules library with your Django models, you'll need to switch\nyour model's base class and metaclass to the extended versions provided in\n``rules.contrib.models``. The extensions are lightweight and only augment the\nmodels by registering permissions. They do not create any migrations for your\nmodels.\n\nThe approach you take depends on whether you're using a custom base class\nand/or metaclass for your models. Here are the steps:\n\n* If you're using the stock ``django.db.models.Model`` as base for your models,\n  simply switch over to ``RulesModel`` and you're good to go.\n* If you're currently using the default ``django.db.models.Model`` as the base\n  for your models, simply switch to using ``RulesModel`` instead, and you're\n  all set.\n* If you already have a custom base class that adds common functionality to\n  your models, you can integrate ``RulesModelMixin`` and set ``RulesModelBase``\n  as the metaclass. Here's how you can do it:\n\n    .. code-block:: python\n\n        from django.db.models import Model\n        from rules.contrib.models import RulesModelBase, RulesModelMixin\n\n        class MyModel(RulesModelMixin, Model, metaclass=RulesModelBase):\n            ...\n\n* If you're using a custom metaclass for your models, you'll know how to\n  ensure it inherits from ``RulesModelBaseMixin``.\n\n  To create your models, assuming you are using ``RulesModel`` as the base\n  class directly, follow this example:\n\n    .. code-block:: python\n\n        import rules\n        from rules.contrib.models import RulesModel\n\n        class Book(RulesModel):\n            class Meta:\n                rules_permissions = {\n                    \"create\": rules.is_staff,\n                    \"retrieve\": rules.is_authenticated,\n                }\n\n  The ``RulesModelMixin`` includes methods that you can override to customize\n  how a model's permissions are registered. For more details, refer to the\n  `django-rules <https://github.com/dfunckt/django-rules>`_ documentation.\n\n\n**NOTE:** The keys of ``rules_permissions`` differ from Django's default name\nconventions (which are also used by ``django-rules``). Instead, we adopt the\nDjango Rest Framework (DRF) conventions. Below is a table showing the default\nCRUD keys for both conventions:\n\n.. list-table:: CRUD key Conventions\n   :header-rows: 1\n\n   * - action\n     - django-rules\n     - drf-rules\n   * - Create\n     - add\n     - create\n   * - Retrieve\n     - view\n     - retrieve\n   * - Update\n     - change\n     - update/partial_update\n   * - Delete\n     - delete\n     - destroy\n   * - List\n     - view\n     - list\n\nAs demonstrated, the keys in `drf-rules` can distinguish directly between\nvarious types of update actions, such as `update` and `partial_update`.\nAdditionally, they can differentiate between `list` and `retrieve` actions.\nThis is because `drf-rules` is designed to align with Django Rest Framework\n(DRF) conventions, enabling it to operate seamlessly with DRF actions.\n\nAnother advantage of using this approach is that it facilitates an automatic\nassociation between rules and Django Rest Framework (DRF) actions. As we will\nsee later, this allows for the seamless integration of `drf-rules` as\npermissions in views.\n\n\nPermissions in views\n++++++++++++++++++++\n\nThis marks the first instance where we utilize ``drf-rules``. You can\nconfigure the ``permission_classes`` attribute for a view or viewset by using\nthe ``ModelViewSet`` class-based views:\n\n.. code-block:: python\n\n  from rest_framework.decorators import action\n  from rest_framework.viewsets import ModelViewSet\n\n  from drf_rules.permissions import AutoRulesPermission\n\n\n  class BookViewSet(ModelViewSet):\n      queryset = Book.objects.all()\n      serializer_class = BookSerializer\n      permission_classes = [AutoRulesPermission]\n\n      @action(detail=False)\n      def custom_nodetail(self, request):\n          return Response({'status': 'request was permitted'})\n\nThis defines permissions based on ``rules_permissions`` specified in the model.\nTo set permissions for custom actions, you can modify ``rules_permissions``.\nFor example, you can do this:\n\n\n.. code-block:: python\n\n  import rules\n  from rules.contrib.models import RulesModel\n\n  class Book(RulesModel):\n      class Meta:\n          rules_permissions = {\n              \"create\": rules.is_staff,\n              \"retrieve\": rules.is_authenticated,\n              \"custom_nodetail\": rules.is_authenticated,\n          }\n\nWith this configuration, the ``custom_nodetail`` action will be allowed only\nto authenticated users. Note that the ``list``, ``update``, ``partial_update``\nand ``destroy`` actions are not explicitly defined. Therefore, the\n``:default:`` rule will be applied. However, since the ``:default:`` rule is\nnot defined, these actions will not be allowed at all. The ``:default:`` rule\nis applicable only to conventional actions, such as ``list``, ``retrieve``,\n``create``, ``update``, ``partial_update``, and ``destroy``. To ensure that\nthe ``:default:`` rule applies to all conventional actions that are not\nexplicitly defined, you can define it accordingly:\n\n.. code-block:: python\n\n  import rules\n  from rules.contrib.models import RulesModel\n\n  class Book(RulesModel):\n      class Meta:\n          rules_permissions = {\n              \"create\": rules.is_staff,\n              \"retrieve\": rules.is_authenticated,\n              \":default:\": rules.is_authenticated,\n          }\n\nIn this case, if ``custom_nodetail`` rule is not explicitly defined,\n``custom_nodetail`` action will not be allowed, even if the ``:default:`` is\nspecified. This is because ``custom_nodetail`` is not a conventional action.\nHowever, the ``:default:`` rule will apply to the ``list``, ``update``,\n``partial_update``, and ``destroy`` actions.\n\n\nLicense\n-------\n\n``drf-rules`` is distributed under the terms of the\n`BSD-3-Clause <https://spdx.org/licenses/BSD-3-Clause.html>`_ license.\n",
    "bugtrack_url": null,
    "license": "BSD-3-Clause",
    "summary": "Rules Permissions with Django DRF",
    "version": "0.0.6",
    "project_urls": {
        "Documentation": "https://github.com/lsaavedr/drf-rules#readme",
        "Issues": "https://github.com/lsaavedr/drf-rules/issues",
        "Source": "https://github.com/lsaavedr/drf-rules"
    },
    "split_keywords": [
        "django",
        " drf",
        " permissions",
        " rules"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e209b30e215c5bf24046ac9b8b4c39df8bad80d085326e4aa8a1ebe84eccedda",
                "md5": "bfea326130df76d7fa5cba263ec7d971",
                "sha256": "8f6bb0bbe8d62fe067eed1cd32bad62f1b68421388bb2d1f757ec46c637e5261"
            },
            "downloads": -1,
            "filename": "drf_rules-0.0.6-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "bfea326130df76d7fa5cba263ec7d971",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 9214,
            "upload_time": "2024-11-08T05:01:07",
            "upload_time_iso_8601": "2024-11-08T05:01:07.214488Z",
            "url": "https://files.pythonhosted.org/packages/e2/09/b30e215c5bf24046ac9b8b4c39df8bad80d085326e4aa8a1ebe84eccedda/drf_rules-0.0.6-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1e4e733f646a4573f87fe67487e2ae2d2cb206ee46f03229acc4f4215755affe",
                "md5": "79d0396c2b35d1e57b48fc78121a7dd4",
                "sha256": "39eb6ae4edb0c5da2f95274bffab1f8518b31d71c3bc82d901fe53cbb5696f54"
            },
            "downloads": -1,
            "filename": "drf_rules-0.0.6.tar.gz",
            "has_sig": false,
            "md5_digest": "79d0396c2b35d1e57b48fc78121a7dd4",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 13878,
            "upload_time": "2024-11-08T05:01:08",
            "upload_time_iso_8601": "2024-11-08T05:01:08.652794Z",
            "url": "https://files.pythonhosted.org/packages/1e/4e/733f646a4573f87fe67487e2ae2d2cb206ee46f03229acc4f4215755affe/drf_rules-0.0.6.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-08 05:01:08",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "lsaavedr",
    "github_project": "drf-rules#readme",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "drf-rules"
}
        
Elapsed time: 1.13964s