diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | python-graphene-django-plus.spec | 1104 | ||||
| -rw-r--r-- | sources | 1 |
3 files changed, 1106 insertions, 0 deletions
@@ -0,0 +1 @@ +/graphene_django_plus-5.0.tar.gz diff --git a/python-graphene-django-plus.spec b/python-graphene-django-plus.spec new file mode 100644 index 0000000..e380aa9 --- /dev/null +++ b/python-graphene-django-plus.spec @@ -0,0 +1,1104 @@ +%global _empty_manifest_terminate_build 0 +Name: python-graphene-django-plus +Version: 5.0 +Release: 1 +Summary: Tools to easily create permissioned CRUD endpoints in graphene. +License: MIT +URL: https://github.com/0soft/graphene-django-plus +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/a9/4e/aea4f90e04e6d7d8c2db0296caca57f23128deddc8378f121a160ee8f3a3/graphene_django_plus-5.0.tar.gz +BuildArch: noarch + + +%description +# graphene-django-plus + +[](https://actions-badge.atrox.dev/0soft/graphene-django-plus/goto?ref=master) +[](https://graphene-django-plus.readthedocs.io) +[](https://codecov.io/gh/0soft/graphene-django-plus) +[](https://pypi.org/project/graphene-django-plus/) + + + +> ## DEPRECATION WARNING +> +> Graphene itself is abandoned and most users are migrating to other better alternatives, like +> [strawberry](https://github.com/strawberry-graphql/strawberry). +> +> For that reason this lib is being deprecated and new features will no longer be developed for it. +> Maintenance is still going to happen and PRs are still welcomed though. +> +> For anyone looking for alternatives, I created +> [strawberry-django-plus](https://github.com/blb-ventures/strawberry-django-plus) to use not +> only as a migration path to the projects I maintain, but also to add even more awesome features. +> Be sure to check it out! + +Tools to easily create permissioned CRUD endpoints in [graphene-django](https://github.com/graphql-python/graphene-django). + +## Install + +```bash +pip install graphene-django-plus +``` + +To make use of everything this lib has to offer, it is recommended to install +both [graphene-django-optimizer](https://github.com/tfoxy/graphene-django-optimizer) +and [django-guardian](https://github.com/django-guardian/django-guardian). + +```bash +pip install graphene-django-optimizer django-guardian +``` + +## What it does + +- Provides some base types for Django Models to improve querying them with: + - Unauthenticated user handling + - Automatic optimization using [graphene-django-optimizer](https://github.com/tfoxy/graphene-django-optimizer) + - Permission handling for queries using the default [django permission system](https://docs.djangoproject.com/en/2.2/topics/auth/default/#topic-authorization) + - Object permission handling for queries using [django guardian](https://github.com/django-guardian/django-guardian) + - Relay id conversion so querying can use the global id instead of the model's id +- Provides a set of complete and simple CRUD mutations with: + - Unauthenticated user handling + - Permission handling using the default [django permission system](https://docs.djangoproject.com/en/2.2/topics/auth/default/#topic-authorization) + - Object permission handling using [django guardian](https://github.com/django-guardian/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](https://graphene-django-plus.readthedocs.io) 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 below to + check for object permissions. + +### 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: + +```py +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 dependent 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 dependent 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: + +```graphql +# 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: + +```py +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 on 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 dependent 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 dependent 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: + +```graphql +# 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](https://python-poetry.org/) installed. + +Install dependencies with: + +```bash +poetry install +``` + +Run the testsuite with: + +```bash +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. + + +%package -n python3-graphene-django-plus +Summary: Tools to easily create permissioned CRUD endpoints in graphene. +Provides: python-graphene-django-plus +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-graphene-django-plus +# graphene-django-plus + +[](https://actions-badge.atrox.dev/0soft/graphene-django-plus/goto?ref=master) +[](https://graphene-django-plus.readthedocs.io) +[](https://codecov.io/gh/0soft/graphene-django-plus) +[](https://pypi.org/project/graphene-django-plus/) + + + +> ## DEPRECATION WARNING +> +> Graphene itself is abandoned and most users are migrating to other better alternatives, like +> [strawberry](https://github.com/strawberry-graphql/strawberry). +> +> For that reason this lib is being deprecated and new features will no longer be developed for it. +> Maintenance is still going to happen and PRs are still welcomed though. +> +> For anyone looking for alternatives, I created +> [strawberry-django-plus](https://github.com/blb-ventures/strawberry-django-plus) to use not +> only as a migration path to the projects I maintain, but also to add even more awesome features. +> Be sure to check it out! + +Tools to easily create permissioned CRUD endpoints in [graphene-django](https://github.com/graphql-python/graphene-django). + +## Install + +```bash +pip install graphene-django-plus +``` + +To make use of everything this lib has to offer, it is recommended to install +both [graphene-django-optimizer](https://github.com/tfoxy/graphene-django-optimizer) +and [django-guardian](https://github.com/django-guardian/django-guardian). + +```bash +pip install graphene-django-optimizer django-guardian +``` + +## What it does + +- Provides some base types for Django Models to improve querying them with: + - Unauthenticated user handling + - Automatic optimization using [graphene-django-optimizer](https://github.com/tfoxy/graphene-django-optimizer) + - Permission handling for queries using the default [django permission system](https://docs.djangoproject.com/en/2.2/topics/auth/default/#topic-authorization) + - Object permission handling for queries using [django guardian](https://github.com/django-guardian/django-guardian) + - Relay id conversion so querying can use the global id instead of the model's id +- Provides a set of complete and simple CRUD mutations with: + - Unauthenticated user handling + - Permission handling using the default [django permission system](https://docs.djangoproject.com/en/2.2/topics/auth/default/#topic-authorization) + - Object permission handling using [django guardian](https://github.com/django-guardian/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](https://graphene-django-plus.readthedocs.io) 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 below to + check for object permissions. + +### 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: + +```py +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 dependent 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 dependent 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: + +```graphql +# 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: + +```py +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 on 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 dependent 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 dependent 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: + +```graphql +# 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](https://python-poetry.org/) installed. + +Install dependencies with: + +```bash +poetry install +``` + +Run the testsuite with: + +```bash +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. + + +%package help +Summary: Development documents and examples for graphene-django-plus +Provides: python3-graphene-django-plus-doc +%description help +# graphene-django-plus + +[](https://actions-badge.atrox.dev/0soft/graphene-django-plus/goto?ref=master) +[](https://graphene-django-plus.readthedocs.io) +[](https://codecov.io/gh/0soft/graphene-django-plus) +[](https://pypi.org/project/graphene-django-plus/) + + + +> ## DEPRECATION WARNING +> +> Graphene itself is abandoned and most users are migrating to other better alternatives, like +> [strawberry](https://github.com/strawberry-graphql/strawberry). +> +> For that reason this lib is being deprecated and new features will no longer be developed for it. +> Maintenance is still going to happen and PRs are still welcomed though. +> +> For anyone looking for alternatives, I created +> [strawberry-django-plus](https://github.com/blb-ventures/strawberry-django-plus) to use not +> only as a migration path to the projects I maintain, but also to add even more awesome features. +> Be sure to check it out! + +Tools to easily create permissioned CRUD endpoints in [graphene-django](https://github.com/graphql-python/graphene-django). + +## Install + +```bash +pip install graphene-django-plus +``` + +To make use of everything this lib has to offer, it is recommended to install +both [graphene-django-optimizer](https://github.com/tfoxy/graphene-django-optimizer) +and [django-guardian](https://github.com/django-guardian/django-guardian). + +```bash +pip install graphene-django-optimizer django-guardian +``` + +## What it does + +- Provides some base types for Django Models to improve querying them with: + - Unauthenticated user handling + - Automatic optimization using [graphene-django-optimizer](https://github.com/tfoxy/graphene-django-optimizer) + - Permission handling for queries using the default [django permission system](https://docs.djangoproject.com/en/2.2/topics/auth/default/#topic-authorization) + - Object permission handling for queries using [django guardian](https://github.com/django-guardian/django-guardian) + - Relay id conversion so querying can use the global id instead of the model's id +- Provides a set of complete and simple CRUD mutations with: + - Unauthenticated user handling + - Permission handling using the default [django permission system](https://docs.djangoproject.com/en/2.2/topics/auth/default/#topic-authorization) + - Object permission handling using [django guardian](https://github.com/django-guardian/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](https://graphene-django-plus.readthedocs.io) 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 below to + check for object permissions. + +### 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: + +```py +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 dependent 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 dependent 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: + +```graphql +# 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: + +```py +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 on 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 dependent 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 dependent 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: + +```graphql +# 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](https://python-poetry.org/) installed. + +Install dependencies with: + +```bash +poetry install +``` + +Run the testsuite with: + +```bash +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. + + +%prep +%autosetup -n graphene-django-plus-5.0 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-graphene-django-plus -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Fri May 05 2023 Python_Bot <Python_Bot@openeuler.org> - 5.0-1 +- Package Spec generated @@ -0,0 +1 @@ +0cc11fec34858651c5ae8b9ced170c34 graphene_django_plus-5.0.tar.gz |
