{ "info": { "author": "Maciej \u0141yskawi\u0144ski", "author_email": "lyskawinski.maciej@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "# Introduction\n\nDGF is a framework for streamlining the writting process using django and graphene.\n\n

Disclaimer

\n\nThis package was initally created for personal project, so it may lack general features you need or have unnecesarry features that you don't need. If you find any of these feel free to leave a issue on [github](https://github.com/LonguCodes/DGF)\n\n# Instalation\n\nThe package can be found on pypi\n\n'pip install django-graphene-framework'\n\n# Dependencies\n\nThis package requires you to install _graphene_ and _django_. If installing using pip the dependencies will be installed automatically\n\n`pip install graphene django`\n\n# Basics\n\nDGF allows you to give easy acces to your models through graphql.\n\nLet's assume we have a model `Profile`\n\n```python\n# models.py\n\nfrom django.db.models import Model,CharField\n\n\nclass Profile(Model):\n first_name = CharField(max_lenght=20)\n last_name = CharField(max_lenght=20)\n```\n\nWe can easily transform it to graphql-accessable model by creating a schema\n\n```python\n# schema.py\n\nfrom DGF import Schema\nfrom .models import Profile\n\nclass ProfileSchema(Schema):\n class Meta:\n model = Profile\n```\n\nWe specify the information in `Meta` class. The `model` field determines of which model is the schema of.\n\nAfter that we have to register the schema, so it can be transformed info graphene's schema\n\nWe create a combiner and the register the schema\n\n```python\n# schema.py\n\nfrom DGF import Schema, Combiner\nfrom .models import Profile\n\nclass ProfileSchema(Schema):\n class Meta:\n model = Profile\n\ncombiner = Combiner()\ncombiner.register(ProfileSchema)\nschema = combiner.to_schema()\n```\n\nThe `schema` can be used like any other graphene schema.\n\n**!!! DGF has not built-in endpoint for graphql as of now !!!**\n\n# Requests\n\nThe schema will generate `query` for the model and `add`, `change` and `delete` mutations.\n\n**Filter parameters** are in form of `(lowercase) _`. Relation fields are excluded.\n\n**Value parameteres** are in form of `(lowercase) `.\nAutofields are excluded. Relations can be provided using ids.\n\n**Return values** are in form of `(lowercase) `.\n\n## Query\n\nThe name of the query will the `Query`. It returns chosen data about the adequate entries.\n\n```graphql\n{\n ProfileQuery(_id: 1) {\n id\n first_name\n last_name\n }\n}\n\n# Will get information about every profile with id = 1\n```\n\n## Mutations\n\nThe name of mutation will be `{Add,Change,Delete}` depending of the type of mutation you want to use.\n\n**Add** mutation can get `value parameters` for the new database entry. It returns chosed data about the added entry.\n\n```graphql\nmutation {\n ProfileAdd(first_name: \"Tom\") {\n id\n first_name\n }\n}\n\n# Will add new profile with first_name = \"Tom\" and return it's id and first_name\n```\n\n**Change** mutation can get `value parameters` for the changed database entry as well as `filter paramters` for which entries to change. It returns chosen data about the changed entries.\n\n```\nmutation {\n ProfileChange(_first_name:\"Tom\", last_name:\"Smith\"){\n first_name\n last_name\n }\n}\n\n# Will change last_name to \"Smith\" of every profile with name \"Tom\" and then return first_name and last_name of these profiles.\n```\n\n**Delete** mutation can get `filter paramteres` for which entries to delete. It returns ids of the deleted entries (will return chosen data in future versions).\n\n```\nmutation {\n ProfileDelete(_last_name:\"Smith\")\n}\n\n# Will delete every entry with last_name = \"Smith\" and return the ids of these entries.\n# Note the lack of {}\n```\n\n# Custom request handling\n\nYou can specify which requests should be possible by overriding `allowed_requests`.\n\n```python\nfrom DGF import Schema, QUERY, ADD\nfrom .models import Profile\n\nallowed_requests = [QUERY,ADD]\n\nclass ProfileSchema(Schema):\n class Meta:\n model = Profile\n```\n\nYou can specify which fields should be accessable by adding `fields` field in `Meta` class of the schema.\n\n```python\n# schema.py\n\nfrom DGF import Schema\nfrom .models import Profile\n\nclass ProfileSchema(Schema):\n class Meta:\n model = Profile\n fields = ['first_name','id']\n\n```\n\nIf `fields` is not defined, all fields will be added.\n\nYou can also add your own fields to the schema.\n\n```python\n# schema.py\nfrom graphene import Int\nfrom DGF import Schema, Field\nfrom .models import Profile\n\nclass ProfileSchema(Schema):\n age = Field(name='age',field=Int()) # The name is required\n\n class Meta:\n model = Profile\n fields = ['first_name','id','age']\n\n```\n\nIf `fields` is not defined, all custom fields will be added. Custom fields will override fields from the model with the same name.\n\n## Custom request logic\n\nCustom fields have to be handled by custom request logic. To add custom request logic you can override a method in the schema.\n\nThe methods accepts parameters:\n\n- `schema` - to which schema this method refers\n- `model` - to which model this method refers\n- `data` - data from the previous link in the chain (for more information read [Pipeline](#Pipeline))\n- `raw_data` - the raw, unprocessed request\n- `params` - additional data (like `schema`, `model`, `raw_data`,`type` and custom data added by the [Pipeline](#pipeline) modules)\n\n### Fetch\n\nFetch method get the data from the database. Name of the fetch method is in form of `fetch_{query,add,change,delete}`. Fetch should return the model / list of models.\n\n### Execute\n\nFetch fucntion execute the request on the provided data. Name of the execute method is in form of `execute_{query,add,change,delete}`. Execute should return the same type as the request's type (see [Query](#query) and [Mutations](#mutations))\n\n# Pipeline\n\nDGF has built-in pipeline that let's you customize the behaviour on every step. The default pipeline is composed of:\n\n- `AuthLink` - tries to authenticate the user based on the provided credentials using authenticatos\n- `RequestPermissionLink` - checks if the user has permission to make this request\n- `FetchLink` - fetches the data from the database about the model\n- `ObjectPermissionLink` - filters the data based on the permission the user has\n- `ExecuteLink` - executes the request (applies only to `Change` and `Delete` mutations by default)\n\nFirst link in the pipeline get's the data from graphene, every other gets the data from previous one.\n\nYou can change the pipeline by setting `DGF_PIPELINE` in the settings.\n\n```python\n# settings.py\n\nDGF_PIPELINE=[\n 'DGF.builtins.FetchPipeline',\n 'DGF.builtins.ExecutePipeline'\n]\n# The bare minimum for everything to work out of the box\n```\n\n### Auth Link\n\nAddes new param `user` that represents the authenticated user (uses the same model as django). The authentication is done using [Authenticators](#authenticators). If it's not possible to authenticate user, sets `user` to `AnonymousUser`.\n\n### Request Permission Link\n\nUses [Permissions](#permissions) to check if the user is suppose to use this request. If not, throws `Unauthorized`.\n\n### Fetch Link\n\nCalls fetch method on the schema (see [Fetch](#fetch)).\n\n### Object Permission Link\n\nUses [Permissions](#permissions) to filter the data.\n\n### Execute Link\n\nCalls execute method on the schema (see [Execute](#execute))\n\n## Custom link\n\nYou can create your own link by overriding the `BaseLink` class and the `process` method inside.\n\n```python\n# links.py\n\nfrom DGF import BaseLink\n\nclass CustomLink(BaseLink):\n def process(self, data):\n # Your custom logic\n return data\n```\n\nYou can get and set additional parameters by using `self.params` or `self.context`.\n\n# Auth\n\n## Authenticators\n\nAuthenticators allow you to authenticate the user without writting custom backend. Parameters for the authentication can be both in body or headers. By default [Model Authenticator](#model-authenticator) is used.\n\n### Model Authenticator\n\nModel authenticator is used for authenticating the user using username and password. It uses Django's default backend.\n\n### Backend Authenticator\n\nBase class for authenticator, that use existing backends. You need to define `args` field with names of all paramateres needed for authentication and it will call django's `authenticate` to try to authenticate the user\n\n```python\nclass ModelAuthenticator(BackendAuthenticator):\n args = ['username', 'password']\n```\n\n### Bearer Authenticator\n\nBase class for authenticator, that user the Bearer token. You need to override the `authenticate_token` method, which should return the user.\n\n```python\nfrom django.conf import settings\nfrom jwt import decode\nfrom django.contrib.auth import get_user_model\nfrom DGF.builtins.authenticators import BearerAuthenticator\n\nclass JWTAuthenticator(BearerAuthenticator):\n @classmethod\n def authenticate_token(cls, token):\n if not token:\n return None\n try:\n decoded = decode(token, settings.SECRET_KEY, algorithms=['HS256'])\n return get_user_model().objects.get(pk=decoded['sub'])\n except:\n return None\n```\n\n### Custom Authenticator\n\nYou can write custom authenticator by overriding `BaseAuthenticator` and `authenticate` method inside as well as `args` field.\n\n```python\n# authenticators.py\nfrom django.contrib.auth import get_user_model\nimport DGF.Authenticator\n\nclass CustomAuthenticator(BaseAuthenticator):\n args = ['username']\n\n @classmethod\n def authenticate(cls,username, **kwargs):\n try:\n return get_user_model().objects.get(username=username)\n except:\n return None\n```\n\n## Permissions\n\nPermissions allow you to limit the user im terms of requests and particular entries.\n\nYou can set permission for each schema by overriding the `permissions` field.\n\n```python\n# schema.py\nfrom DGF import Schema\nfrom DGF.builtins import ReadOnlyPermission\nfrom .models import Profile\n\nclass ProfileSchema(Schema):\n class Meta:\n model = Profile\n\n permissions = [ReadOnlyPermission]\n```\n\n### Read Only Permission\n\nAllows only `Query` requests.\n\n### Custom permissions\n\nYou can write your own permissions by overriding `BasePermissions` class as well as overriding one or more of the methods:\n\n- `has_object_permission` - for [Object Permission Link](#object-permission-link)\n- `has_request_permission` - for [Request Permission Link](#request-permission-link)\n\nBoth methods can accept `schema`, `model`, `data` and `params`.\n\n```python\n# permission.py\n\nfrom DGF import BasePermission\n\nclass IsAuthenticated(BasePermission):\n @staticmethod\n def has_request_permission(params, **kwargs):\n return params['user'].is_authenticated\n\n\nclass IsOwner(BasePermission):\n @staticmethod\n def has_object_permission(schema, data, params, **kwargs):\n return getattr(data,'owner',None) == params['user']\n\n```\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/LonguCodes/DGF/", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "django-graphene-framework", "package_url": "https://pypi.org/project/django-graphene-framework/", "platform": "", "project_url": "https://pypi.org/project/django-graphene-framework/", "project_urls": { "Homepage": "https://github.com/LonguCodes/DGF/" }, "release_url": "https://pypi.org/project/django-graphene-framework/0.0.2/", "requires_dist": [ "django", "graphene" ], "requires_python": "", "summary": "Framework to streamline working with django and graphene", "version": "0.0.2" }, "last_serial": 5752557, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "e039bc479b1e0df9e67e1e1da0d9a7b6", "sha256": "2b38961c3e321a8c1d86867324d49b289c8e158ab914b965ef2aadbc564a2b60" }, "downloads": -1, "filename": "django_graphene_framework-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "e039bc479b1e0df9e67e1e1da0d9a7b6", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20463, "upload_time": "2019-08-12T17:11:50", "url": "https://files.pythonhosted.org/packages/b1/f7/783b9fcf2ed888e7ce6bd82d548ee0d5869411850f97cea6ad2ee937dfad/django_graphene_framework-0.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6c33ad322cfccb2a2e74614ec6cff299", "sha256": "3f285e265b71a4e1bee50c0e476bcc2d8ba919013183816fb32560a969ae2804" }, "downloads": -1, "filename": "django-graphene-framework-0.0.1.tar.gz", "has_sig": false, "md5_digest": "6c33ad322cfccb2a2e74614ec6cff299", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12949, "upload_time": "2019-08-12T17:11:53", "url": "https://files.pythonhosted.org/packages/34/b0/d7c35795159b534fd75dbe6c738da2eb5f131ce65db16ccb74d80baebe60/django-graphene-framework-0.0.1.tar.gz" } ], "0.0.1.post1": [ { "comment_text": "", "digests": { "md5": "0192614127727da6412b442b1f020bb3", "sha256": "3b82e4aa9db82416b861be4146c84431abe9021978bc3e7b703a4625f4a8c96c" }, "downloads": -1, "filename": "django_graphene_framework-0.0.1.post1-py3-none-any.whl", "has_sig": false, "md5_digest": "0192614127727da6412b442b1f020bb3", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20539, "upload_time": "2019-08-13T11:34:36", "url": "https://files.pythonhosted.org/packages/8e/5a/2d3edc528bbc9bd8a09672d71567da9496ac841c6ddb1779cf4f7c690a37/django_graphene_framework-0.0.1.post1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "47158062ad907e41eb49d2f549a67695", "sha256": "bbeee847e2c197f8d106774d49659930f9fd7c029719fb1e4829fae08c0347e9" }, "downloads": -1, "filename": "django-graphene-framework-0.0.1.post1.tar.gz", "has_sig": false, "md5_digest": "47158062ad907e41eb49d2f549a67695", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12973, "upload_time": "2019-08-13T11:34:38", "url": "https://files.pythonhosted.org/packages/dd/e9/bf7bb6be6fe872ed786f2d0e5a408c784fdcd6b1c1b2bf4d99cfcbc36d59/django-graphene-framework-0.0.1.post1.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "5e51e5d319e5fe0420d84376a6df55e2", "sha256": "87aa4d789b31b9f4ff5002a45fc1ff6e5f407a72287cf8aadf3d33be7cbdea5a" }, "downloads": -1, "filename": "django_graphene_framework-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "5e51e5d319e5fe0420d84376a6df55e2", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20592, "upload_time": "2019-08-29T13:28:32", "url": "https://files.pythonhosted.org/packages/87/6e/05b075841f30bee681f6bfab21e2bb48b4d1a83f77ffd27b5c410ed690cd/django_graphene_framework-0.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "819763ee25b4b4d63ae55df7f19732e0", "sha256": "375351aa085cbf5f8ff03710a2f9371a561e82cdb07f276deba111425e0c7eb2" }, "downloads": -1, "filename": "django-graphene-framework-0.0.2.tar.gz", "has_sig": false, "md5_digest": "819763ee25b4b4d63ae55df7f19732e0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13046, "upload_time": "2019-08-29T13:28:33", "url": "https://files.pythonhosted.org/packages/4c/26/9bc7a46505c2630bc66240fed717ac6903d3acd3baad4ff859273822261b/django-graphene-framework-0.0.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "5e51e5d319e5fe0420d84376a6df55e2", "sha256": "87aa4d789b31b9f4ff5002a45fc1ff6e5f407a72287cf8aadf3d33be7cbdea5a" }, "downloads": -1, "filename": "django_graphene_framework-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "5e51e5d319e5fe0420d84376a6df55e2", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20592, "upload_time": "2019-08-29T13:28:32", "url": "https://files.pythonhosted.org/packages/87/6e/05b075841f30bee681f6bfab21e2bb48b4d1a83f77ffd27b5c410ed690cd/django_graphene_framework-0.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "819763ee25b4b4d63ae55df7f19732e0", "sha256": "375351aa085cbf5f8ff03710a2f9371a561e82cdb07f276deba111425e0c7eb2" }, "downloads": -1, "filename": "django-graphene-framework-0.0.2.tar.gz", "has_sig": false, "md5_digest": "819763ee25b4b4d63ae55df7f19732e0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13046, "upload_time": "2019-08-29T13:28:33", "url": "https://files.pythonhosted.org/packages/4c/26/9bc7a46505c2630bc66240fed717ac6903d3acd3baad4ff859273822261b/django-graphene-framework-0.0.2.tar.gz" } ] }