Skip to main content

Tools to easily create permissioned CRUD endpoints in graphene.

Project description

graphene-django-plus

build status docs status coverage PyPI version python version django version

Tools to easily create permissioned CRUD endpoints in graphene-django.

Install

pip install graphene-django-plus

To make use of everything this lib has to offer, it is recommended to install both graphene-django-optimizer and django-guardian.

pip install graphene-django-optimizer django-guardian

What it does

  • Provides some base types for Django Models to improve querying them with:
  • Provides a set of complete and simple CRUD mutations with:
    • Unauthenticated user handling
    • Permission handling using the default django permission system
    • Object permission handling using django guardian
    • Automatic input generation based on the model (no need to write your own input type or use django forms and drf serializers)
    • Automatic model validation based on the model's validators
  • Very simple to create some quick CRUD endpoints for your models
  • Easy to extend and override functionalities
  • File upload handling

What is included

Check the docs for a complete api documentation.

Models

  • graphene_django_plus.models.GuardedModel: A django model that can be used either directly or as a mixin. It will provide a .has_perm method and a .objects.for_user that will be used by ModelType described bellow to check for object permissions. some utilities to check.

Types and Queries

  • graphene_django_plus.types.ModelType: This enchances graphene_django_plus.DjangoModelType by doing some automatic prefetch optimization on setup and also checking for objects permissions on queries when it inherits from GuardedModel.

  • graphene_django_plus.fields.CountableConnection: This enchances graphene.relay.Connection to provide a total_count attribute.

Here is an example describing how to use those:

import graphene
from graphene import relay
from graphene_django.fields import DjangoConnectionField

from graphene_django_plus.models import GuardedModel
from graphene_django_plus.types import ModelType
from graphene_django_plus.fields import CountableConnection


class MyModel(GuardedModel):
    class Meta:
        # guardian permissions for this model
        permissions = [
            ('can_read', "Can read the this object's info."),
        ]

    name = models.CharField(max_length=255)


class MyModelType(ModelType):
    class Meta:
        model = MyModel
        interfaces = [relay.Node]

        # Use our CountableConnection
        connection_class = CountableConnection

        # When adding this to a query, only objects with a `can_read`
        # permission to the request's user will be allowed to return to him
        # Note that `can_read` was defined in the model.
        # If the model doesn't inherid from `GuardedModel`, `guardian` is not
        # installed or this list is empty, any object will be allowed.
        # This is empty by default
        object_permissions = [
            'can_read',
        ]

        # If unauthenticated users should be allowed to retrieve any object
        # of this type. This is not dependant on `GuardedModel` and neither
        # `guardian` and is defined as `False` by default
        public = False

        # A list of Django model permissions to check. Different from
        # object_permissions, this uses the basic Django's permission system
        # and thus is not dependant on `GuardedModel` and neither `guardian`.
        # This is an empty list by default.
        permissions = []


class Query(graphene.ObjectType):
    my_models = DjangoConnectionField(MyModelType)
    my_model = relay.Node.Field(MyModelType)

This can be queried like:

# All objects that the user has permission to see
query {
  myModels {
    totalCount
    edges {
      node {
        id
        name
      }
    }
  }
}

# Single object if the user has permission to see it
query {
  myModel(id: "<relay global ID>") {
    id
    name
  }
}

Mutations

  • graphene_django_plus.mutations.BaseMutation: Base mutation using relay and some basic permission checking. Just override its .perform_mutation to perform the mutation.

  • graphene_django_plus.mutations.ModelMutation: Model mutation capable of both creating and updating a model based on the existence of an id attribute in the input. All the model's fields will be automatically read from Django, inserted in the input type and validated.

  • graphene_django_plus.mutations.ModelCreateMutation: A ModelMutation enforcing a "create only" rule by excluding the id field from the input.

  • graphene_django_plus.mutations.ModelUpdateMutation: A ModelMutation enforcing a "update only" rule by making the id field required in the input.

  • graphene_django_plus.mutations.ModelDeleteMutation: A mutation that will receive only the model's id and will delete it (if given permission, of course).

Here is an example describing how to use those:

import graphene
from graphene import relay

from graphene_django_plus.models import GuardedModel
from graphene_django_plus.types import ModelType
from graphene_django_plus.mutations import (
    ModelCreateMutation,
    ModelUpdateMutation,
    ModelDeleteMutation,
)


class MyModel(GuardedModel):
    class Meta:
        # guardian permissions for this model
        permissions = [
            ('can_write', "Can update this object's info."),
        ]

    name = models.CharField(max_length=255)


class MyModelType(ModelType):
    class Meta:
        model = MyModel
        interfaces = [relay.Node]


class MyModelUpdateMutation(ModelUpdateMutation):
    class Meta:
        model = MyModel

        # Make sure only users with the given permissions can modify the
        # object.
        # If the model doesn't inherid from `GuardedModel`, `guardian` is not
        # installed ot this list is empty, any object will be allowed.
        # This is empty by default.
        object_permissions = [
            'can_write',
        ]

        # If unauthenticated users should be allowed to retrieve any object
        # of this type. This is not dependant on `GuardedModel` and neither
        # `guardian` and is defined as `False` by default
        public = False

        # A list of Django model permissions to check. Different from
        # object_permissions, this uses the basic Django's permission system
        # and thus is not dependant on `GuardedModel` and neither `guardian`.
        # This is an empty list by default.
        permissions = []


class MyModelDeleteMutation(ModelDeleteMutation):
    class Meta:
        model = MyModel
        object_permissions = [
            'can_write',
        ]


class MyModelCreateMutation(ModelCreateMutation):
    class Meta:
        model = MyModel

    @classmethod
    def after_save(cls, info, instance, cleaned_input=None):
        # If the user created the object, allow him to modify it
        assign_perm('can_write', info.context.user, instance)


class Mutation(graphene.ObjectType):
    my_model_create = MyModelCreateMutation.Field()
    my_model_update = MyModelUpdateMutation.Field()
    my_model_delete = MyModelDeleteMutation.Field()

This can be used to create/update/delete like:

# Create mutation
mutation {
  myModelCreate(input: {name: "foobar"}) {
    myModel {
      name
    }
    errors {
      field
      message
    }
  }
}

# Update mutation
mutation {
  myModelUpdate(input: {id: "<relay global ID>" name: "foobar"}) {
    myModel {
      name
    }
    errors {
      field
      message
    }
  }
}

# Delete mutation
mutation {
  myModelDelete(input: {id: "<relay global ID>"}) {
    myModel {
      name
    }
    errors {
      field
      message
    }
  }
}

Any validation errors will be presented in the errors return value.

To turn off auto related relations addition to the mutation input - set global MUTATIONS_INCLUDE_REVERSE_RELATIONS parameter to False in your settings.py:

GRAPHENE_DJANGO_PLUS = {
    'MUTATIONS_INCLUDE_REVERSE_RELATIONS': False
}

Note: in case reverse relation does not have related_name attribute set - mutation input will be generated as Django itself is generating by appending _set to the lower cased model name - modelname_set

License

This project is licensed under MIT licence (see LICENSE for more info)

Contributing

Make sure to have poetry installed.

Install dependencies with:

poetry install

Run the testsuite with:

poetry run pytest

Feel free to fork the project and send me pull requests with new features, corrections and translations. We'll gladly merge them and release new versions ASAP.

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

graphene-django-plus-3.2.tar.gz (24.7 kB view details)

Uploaded Source

Built Distribution

graphene_django_plus-3.2-py3-none-any.whl (25.1 kB view details)

Uploaded Python 3

File details

Details for the file graphene-django-plus-3.2.tar.gz.

File metadata

  • Download URL: graphene-django-plus-3.2.tar.gz
  • Upload date:
  • Size: 24.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.11 CPython/3.8.2 Linux/5.8.0-1042-azure

File hashes

Hashes for graphene-django-plus-3.2.tar.gz
Algorithm Hash digest
SHA256 2e230d1fad7aa673c99901a029a44a1403f77b69b7d10904999403b50155c103
MD5 c98d39181a45a3017f0d6dbe6418be36
BLAKE2b-256 10d4b21320811d18a7735b5f78a5ad10dbc765287d39a652b0fe6c874ebd6a02

See more details on using hashes here.

File details

Details for the file graphene_django_plus-3.2-py3-none-any.whl.

File metadata

  • Download URL: graphene_django_plus-3.2-py3-none-any.whl
  • Upload date:
  • Size: 25.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.11 CPython/3.8.2 Linux/5.8.0-1042-azure

File hashes

Hashes for graphene_django_plus-3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 b91841a2efb9348370603516afefd4ce335fbe4cc69e4281e30d1996962d46ed
MD5 2a62d9c1bccc625a5cb6c84b1ec6843b
BLAKE2b-256 3128d432202af2fb7411c3136c318f9fa60b43c4b40d2de734c46566e907b4a6

See more details on using hashes here.

Supported by

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