graphene-django-extras


Namegraphene-django-extras JSON
Version 1.0.0 PyPI version JSON
download
home_pagehttps://github.com/eamigo86/graphene-django-extras
SummaryThis library add some extra funcionalities to graphene-django to facilitate the graphql use without Relay, allow paginations and filtering integration and add some extra directives
upload_time2023-01-23 09:26:30
maintainer
docs_urlNone
authorErnesto Perez Amigo
requires_python>=3.7,<4.0
licenseMIT
keywords api graphql protocol graphene django
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            
---

# Graphene-Django-Extras
![Travis (.org) branch](https://img.shields.io/travis/eamigo86/graphene-django-extras/master)
![Codecov](https://img.shields.io/codecov/c/github/eamigo86/graphene-django-extras)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/graphene-django-extras)
![PyPI](https://img.shields.io/pypi/v/graphene-django-extras?color=blue)
![PyPI - License](https://img.shields.io/pypi/l/graphene-django-extras)
![PyPI - Downloads](https://img.shields.io/pypi/dm/graphene-django-extras?style=flat)
![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)

This package adds some extra functionalities to graphene-django to facilitate the graphql use without Relay:
  1. Allow pagination and filtering on Queries.
  2. Allow defining DjangoRestFramework serializers based on Mutations.
  3. Allow using Directives on Queries and Fragments.

**NOTE:** Subscription support was moved to [graphene-django-subscriptions](https://github.com/eamigo86/graphene-django-subscriptions).

## Installation

For installing graphene-django-extras, just run this command in your shell:

```
pip install graphene-django-extras
```

## Documentation:

### Extra functionalities:
 **Fields:**
  1.  DjangoObjectField
  2.  DjangoFilterListField
  3.  DjangoFilterPaginateListField
  4.  DjangoListObjectField (*Recommended for Queries definition*)

 **Mutations:**
  1.  DjangoSerializerMutation (*Recommended for Mutations definition*)

 **Types:**
  1.  DjangoListObjectType  (*Recommended for Types definition*)
  2.  DjangoInputObjectType
  3.  DjangoSerializerType  (*Recommended for quick queries and mutations definitions*)

 **Paginations:**
  1.  LimitOffsetGraphqlPagination
  2.  PageGraphqlPagination


### Queries and Mutations examples:

This is a basic example of graphene-django-extras package use. You can configure global params
for DjangoListObjectType classes pagination definitions on settings.py like this:

```python
    GRAPHENE_DJANGO_EXTRAS = {
        'DEFAULT_PAGINATION_CLASS': 'graphene_django_extras.paginations.LimitOffsetGraphqlPagination',
        'DEFAULT_PAGE_SIZE': 20,
        'MAX_PAGE_SIZE': 50,
        'CACHE_ACTIVE': True,
        'CACHE_TIMEOUT': 300    # seconds
    }
```

#### 1- Types Definition:

```python
from django.contrib.auth.models import User
from graphene_django_extras import DjangoListObjectType, DjangoSerializerType, DjangoObjectType
from graphene_django_extras.paginations import LimitOffsetGraphqlPagination

from .serializers import UserSerializer


class UserType(DjangoObjectType):
    class Meta:
        model = User
        description = " Type definition for a single user "
        filter_fields = {
            "id": ("exact", ),
            "first_name": ("icontains", "iexact"),
            "last_name": ("icontains", "iexact"),
            "username": ("icontains", "iexact"),
            "email": ("icontains", "iexact"),
            "is_staff": ("exact", ),
        }


class UserListType(DjangoListObjectType):
    class Meta:
        description = " Type definition for user list "
        model = User
        pagination = LimitOffsetGraphqlPagination(default_limit=25, ordering="-username") # ordering can be: string, tuple or list


class UserModelType(DjangoSerializerType):
    """ With this type definition it't necessary a mutation definition for user's model """

    class Meta:
        description = " User model type definition "
        serializer_class = UserSerializer
        pagination = LimitOffsetGraphqlPagination(default_limit=25, ordering="-username") # ordering can be: string, tuple or list
        filter_fields = {
            "id": ("exact", ),
            "first_name": ("icontains", "iexact"),
            "last_name": ("icontains", "iexact"),
            "username": ("icontains", "iexact"),
            "email": ("icontains", "iexact"),
            "is_staff": ("exact", ),
        }
```

#### 2- You can to define InputTypes for use on mutations:

```python
from graphene_django_extras import DjangoInputObjectType


class UserInput(DjangoInputObjectType):
    class Meta:
        description = " User InputType definition to use as input on an Arguments class on traditional Mutations "
        model = User
```

#### 3- You can define traditional mutations that use InputTypes or Mutations based on DRF serializers:

```python
import graphene
from graphene_django_extras import DjangoSerializerMutation

from .serializers import UserSerializer
from .types import UserType
from .input_types import UserInputType


class UserSerializerMutation(DjangoSerializerMutation):
    """
        DjangoSerializerMutation auto implement Create, Delete and Update functions
    """
    class Meta:
        description = " DRF serializer based Mutation for Users "
        serializer_class = UserSerializer


class UserMutation(graphene.Mutation):
    """
         On traditional mutation classes definition you must implement the mutate function

    """

    user = graphene.Field(UserType, required=False)

    class Arguments:
        new_user = graphene.Argument(UserInput)

    class Meta:
        description = " Graphene traditional mutation for Users "

    @classmethod
    def mutate(cls, root, info, *args, **kwargs):
        ...
```

#### 4- Defining the Schema file:

```python
import graphene
from graphene_django_extras import DjangoObjectField, DjangoListObjectField, DjangoFilterPaginateListField,
DjangoFilterListField, LimitOffsetGraphqlPagination
from .types import UserType, UserListType, UserModelType
from .mutations import UserMutation, UserSerializerMutation


class Queries(graphene.ObjectType):
    # Possible User list queries definitions
    users = DjangoListObjectField(UserListType, description='All Users query')
    users1 = DjangoFilterPaginateListField(UserType, pagination=LimitOffsetGraphqlPagination())
    users2 = DjangoFilterListField(UserType)
    users3 = DjangoListObjectField(UserListType, filterset_class=UserFilter, description='All Users query')

    # Defining a query for a single user
    # The DjangoObjectField have a ID type input field, that allow filter by id and is't necessary to define resolve function
    user = DjangoObjectField(UserType, description='Single User query')

    # Another way to define a query to single user
    user1 = UserListType.RetrieveField(description='User List with pagination and filtering')

    # Exist two ways to define single or list user queries with DjangoSerializerType
    user_retrieve1, user_list1 = UserModelType.QueryFields(
        description='Some description message for both queries',
        deprecation_reason='Some deprecation message for both queries'
    )
    user_retrieve2 = UserModelType.RetrieveField(
        description='Some description message for retrieve query',
        deprecation_reason='Some deprecation message for retrieve query'
    )
    user_list2 = UserModelType.ListField(
        description='Some description message for list query',
        deprecation_reason='Some deprecation message for list query'
    )

class Mutations(graphene.ObjectType):
    user_create = UserSerializerMutation.CreateField(deprecation_reason='Some one deprecation message')
    user_delete = UserSerializerMutation.DeleteField()
    user_update = UserSerializerMutation.UpdateField()

    # Exist two ways to define mutations with DjangoSerializerType
    user_create1, user_delete1, user_update1 = UserModelType.MutationFields(
        description='Some description message for create, delete and update mutations',
        deprecation_reason='Some deprecation message for create, delete and update mutations'
    )

    user_create2 = UserModelType.CreateField(description='Description message for create')
    user_delete2 = UserModelType.DeleteField(description='Description message for delete')
    user_update2 = UserModelType.UpdateField(description='Description message for update')

    traditional_user_mutation = UserMutation.Field()
```

#### 5- Directives settings:
For use Directives you must follow two simple steps:
1. You must add **'graphene_django_extras.ExtraGraphQLDirectiveMiddleware'** to your GRAPHENE dict
config on your settings.py:

```python
# settings.py

GRAPHENE = {
    'SCHEMA_INDENT': 4,
    'MIDDLEWARE': [
        'graphene_django_extras.ExtraGraphQLDirectiveMiddleware'
    ]
}
```

2. You must add the *directives* param with your custom directives to your schema definition. This module comes with
some common directives for you, these directives allow to you format strings, numbers, lists, and dates (optional), and
you can load like this:

```python
# schema.py
from graphene_django_extras import all_directives

schema = graphene.Schema(
    query=RootQuery,
    mutation=RootMutation,
    directives=all_directives
)
```
**NOTE**: Date directive depends on *dateutil* module, so if you do not have installed it, this directive will not be
available. You can install *dateutil* module manually:
```
pip install python-dateutil
```
or like this:
```
pip install graphene-django-extras[date]
```
That's all !!!


#### 6- Complete Directive list:

##### FOR NUMBERS:
1. **FloorGraphQLDirective**: Floors value. Supports both String and Float fields.
2. **CeilGraphQLDirective**: Ceils value. Supports both String and Float fields.

##### FOR LIST:
1. **ShuffleGraphQLDirective**: Shuffle the list in place.
2. **SampleGraphQLDirective**: Take a 'k' int argument and return a k length list of unique elements chosen from the
taken list

##### FOR DATE:
1. **DateGraphQLDirective**: Take a optional 'format' string argument and format the date from resolving the field by
dateutil module with the 'format' format. Default format is: 'DD MMM YYYY HH:mm:SS' equivalent to
'%d %b %Y %H:%M:%S' python format.

##### FOR STRING:
1. **DefaultGraphQLDirective**: Take a 'to' string argument. Default to given value if None or ""
2. **Base64GraphQLDirective**: Take a optional ("encode" or "decode") 'op' string argument(default='encode').
Encode or decode the string taken.
3. **NumberGraphQLDirective**: Take a 'as' string argument. String formatting like a specify Python number formatting.
4. **CurrencyGraphQLDirective**: Take a optional 'symbol' string argument(default="$").
Prepend the *symbol* argument to taken string and format it like a currency.
5. **LowercaseGraphQLDirective**: Lowercase the taken string.
6. **UppercaseGraphQLDirective**: Uppercase the taken string.
7. **CapitalizeGraphQLDirective**: Return the taken string with its first character capitalized and the rest lowered.
8. **CamelCaseGraphQLDirective**: CamelCase the taken string.
9. **SnakeCaseGraphQLDirective**: SnakeCase the taken string.
10. **KebabCaseGraphQLDirective**: SnakeCase the taken string.
11. **SwapCaseGraphQLDirective**: Return the taken string with uppercase characters converted to lowercase and vice
versa.
12. **StripGraphQLDirective**: Take a optional 'chars' string argument(default=" ").
Return the taken string with the leading and trailing characters removed. The 'chars' argument is not a prefix or
suffix; rather, all combinations of its values are stripped.
13. **TitleCaseGraphQLDirective**: Return the taken string title-cased, where words start with an uppercase character
and the remaining characters are lowercase.
14. **CenterGraphQLDirective**: Take a 'width' string argument and a optional 'fillchar' string argument(default=" ").
Return the taken string centered with the 'width' argument as new length. Padding is done using the specified
'fillchar' argument. The original string is returned if 'width' argument is less than or equal to taken string
length.
15. **ReplaceGraphQLDirective**: Take two strings arguments 'old' and 'new', and a optional integer argument
'count'.
Return the taken string with all occurrences of substring 'old' argument replaced by 'new' argument value.
If the optional argument 'count' is given, only the first 'count' occurrences are replaced.


#### 7- Queries's examples:
```js
{
  allUsers(username_Icontains:"john"){
    results(limit:5, offset:5){
      id
      username
      firstName
      lastName
    }
    totalCount
  }

  allUsers1(lastName_Iexact:"Doe", limit:5, offset:0){
    id
    username
    firstName
    lastName
  }

  allUsers2(firstName_Icontains: "J"){
    id
    username
    firstName
    lastName
  }

  user(id:2){
    id
    username
    firstName
  }

  user1(id:2){
    id
    username
    firstName
  }
}
```

#### 8- Mutations's examples:

```js
mutation{
  userCreate(newUser:{username:"test", password:"test*123"}){
    user{
      id
      username
      firstName
      lastName
    }
    ok
    errors{
      field
      messages
    }
  }

  userDelete(id:1){
    ok
    errors{
      field
      messages
    }
  }

  userUpdate(newUser:{id:1, username:"John"}){
    user{
      id
      username
    }
    ok
    errors{
      field
      messages
    }
  }
}
```

#### 9- Directives's examples:
Let's suppose that we have this query:
```js
query{
    allUsers{
        result{
            id
            firstName
            lastName
            dateJoined
            lastLogin
        }
    }
}
```
And return this data:
```js
{
  "data": {
    "allUsers": {
      "results": [
        {
            "id": "1",
            "firstName": "JOHN",
            "lastName": "",
            "dateJoined": "2017-06-20 09:40:30",
            "lastLogin": "2017-08-05 21:05:02"
        },
        {
            "id": "2",
            "firstName": "Golden",
            "lastName": "GATE",
            "dateJoined": "2017-01-02 20:36:45",
            "lastLogin": "2017-06-20 10:15:31"
        },
        {
            "id": "3",
            "firstName": "Nike",
            "lastName": "just do it!",
            "dateJoined": "2017-08-30 16:05:20",
            "lastLogin": "2017-12-05 09:23:09"
        }
      ]
    }
  }
}
```
As we see, some data it's missing or just not have the format that we like it, so let's go to format the output data
that we desired:
```js
query{
    allUsers{
        result{
            id
            firstName @capitalize
            lastName @default(to: "Doe") @title_case
            dateJoined @date(format: "DD MMM YYYY HH:mm:SS")
            lastLogin @date(format: "time ago")
        }
    }
}
```
And we get this output data:
```js
{
  "data": {
    "allUsers": {
      "results": [
        {
            "id": "1",
            "firstName": "John",
            "lastName": "Doe",
            "dateJoined": "20 Jun 2017 09:40:30",
            "lastLogin": "4 months, 12 days, 15 hours, 27 minutes and 58 seconds ago"
        },
        {
            "id": "2",
            "firstName": "Golden",
            "lastName": "Gate",
            "dateJoined": "02 Jan 2017 20:36:45",
            "lastLogin": "5 months, 28 days, 2 hours, 17 minutes and 53 seconds ago"
        },
        {
            "id": "3",
            "firstName": "Nike",
            "lastName": "Just Do It!",
            "dateJoined": "30 Aug 2017 16:05:20",
            "lastLogin": "13 days, 3 hours, 10 minutes and 31 seconds ago"
        }
      ]
    }
  }
}
```
As we see, the directives are an easy way to format output data on queries, and it's can be put together like a chain.

**List of possible date's tokens**:
"YYYY", "YY", "WW", "W", "DD", "DDDD", "d", "ddd", "dddd", "MM", "MMM", "MMMM", "HH", "hh", "mm", "ss", "A", "ZZ", "z".

You can use this shortcuts too:

1. "time ago"
2. "iso": "YYYY-MMM-DDTHH:mm:ss"
3. "js" or "javascript": "ddd MMM DD YYYY HH:mm:ss"


## Change Log:

#### v1.0.0:
    1. Added support to Django 4.x
    2. Removed support for Django versions < 3.2

#### v0.5.1:
    1. Update dependencies

#### v0.5.0:
    1. Upgrade to graphene v3

#### v0.4.8:
    1. Upgrade graphene-django dependency to version == 2.6.0.

#### v0.4.6:
    1. Upgrade graphql-core dependency to version >= 2.2.1.
    2. Upgrade graphene dependency to version >= 2.1.8.
    3. Upgrade graphene-django dependency to version >= 2.5.0.
    4. Upgrade django-filter dependency to version >= 2.2.0.
    5. Fixed bug 'DjangoSerializerOptions' object has no attribute 'interfaces' after update to graphene==2.1.8.
    6. The tests were refactored and added some extra tests for DjangoSerializerType.

#### v0.4.5:
    1. Fixed compatibilities issues to use graphene-django>=2.3.2.
    2. Improved code quality and use Black code format.
    3. Fixed minor bug with "time ago" date directive.

#### v0.3.7:
    1. Improved DjangoListType and DjangoObjectType to share the filterset_class between the two class.

#### v0.3.6:
    1. Improve DjangoSerializerMutation resolvers.

#### v0.3.5:
    1. Fixed minor bug on ExtraGraphQLDirectiveMiddleware.
    2. Fixed error with DRF 3.8 Compatibility.
    3. Updated List's Fields to pass info.context to filterset as request, this allow filtering by request data.
    4. Added new feature to ordering paginated queries.

#### v0.3.4-alpha2:
    1. Fixed minor bug on DjangoListObjectType.

#### v0.3.4-alpha1:
    1. Added filterset_class to the listing types as default filter.
    2. Changed getOne by RetrieveField on DjangoListObjectType.

####  v0.3.3:
    1. Added filterset_class to DjangoObjectType.
    2. Fixed minor bug on factory_types function.

####  v0.3.3-alpha1:
    1. Fixed minor bug on *queryset_factory* function.

#### v0.3.2:
    1. Updated Date directive format function for better string format combinations.
    2. Updated custom Time, Date and DateTime base types to be used with Date directive.
    3. Fixed bug with caching Introspection queries on ExtraGraphQLView.

#### v0.3.1:
    1. Fixed bug with default Date directive format.

#### v0.3.0:
    1. Added Binary graphql type. A BinaryArray is used to convert a Django BinaryField to the string form.
    2. Added 'CACHE_ACTIVE' and 'CACHE_TIMEOUT' config options to GRAPHENE_DJANGO_EXTRAS settings for activate cache and
     define a expire time. Default values are: CACHE_ACTIVE=False, CACHE_TIMEOUT=300 (seconds). Only available for
     Queries.
    3. Updated Date directive for use with Django TimeField, DateField, and DateTimeField.
    4. Updated ExtraGraphQLView and AuthenticatedGraphQLView to allow use subscription requests on graphene-django >=2.0
    5. Updated setup dependence to graphene-django>=2.0.

#### v0.2.2:
    1. Fixed performance bug on some queries when request nested ManyToMany fields.

#### v0.2.1:
    1. Fixed bug with default PaginationClass and DjangoFilterPaginateListField.

#### v0.2.0:
    1. Added some useful directives to use on queries and fragments.
    2. Fixed error on DjangoFilterPaginateListField resolve function.

#### v0.1.6:
    1. Fixed bug on create and update function on serializer mutation.

#### v0.1.3:
    1. Fixed minors  bugs.

#### v0.1.2:
    1. Added ok field and errors field to DjangoSerializerType like on DjangoSerializerMutation.
    2. Added possibility of filtering in those queries fields that return a list of objects.
    3. Updated DRF compatibility.
    4. Fixed bug with filters when use global DEFAULT_PAGINATION_CLASS.

#### v0.1.1:
    1. Fixed error with JSONField reference on Django==1.8.x installations.

#### v0.1.0:
    1. Added DjangoSerializerType for quick Django's models types definition (See documentation).
    2. Moved support for Subscriptions to graphene-django-subscriptions packages for
    incompatibility with graphene-django>=2.0.
    3. Fixed bug on DjangoFilterPaginateListField's pagination.

#### v0.1.0-alpha12:
    1. Added new settings param: MAX_PAGE_SIZE, to use on GRAPHENE_DJANGO_EXTRAS
    configuration dict for better customize DjangoListObjectType's pagination.
    2. Added support to Django's field: GenericRel.
    3. Improve model's fields calculation for to add all possible related and reverse fields.
    4. Improved documentation translation.

#### v0.1.0-alpha11:
    1. Improved ordering for showed fields on graphqli's IDE.
    2. Added better descriptions for auto generated fields.

#### v0.1.0-alpha10:
    1. Improve converter.py file to avoid create field for auto generate OneToOneField
    product of an inheritance.
    2. Fixed bug in Emun generation for fields with choices of model inheritance child.

#### v0.1.0-alpha9:
    1. Fixed bug on GenericType and GenericInputType generations for
    Queries list Type and Mutations.

#### v0.1.0-alpha6:
    1. Fixed with exclude fields and converter function.

#### v0.1.0-alpha5:
    1. Updated dependencies to graphene-django>=2.0.
    2. Fixed minor bugs on queryset_builder performance.

#### v0.1.0-alpha4:
    1.  Add queryset options to DjangoListObjectType Meta class for specify wanted model queryset.
    2.  Add AuthenticatedGraphQLView on graphene_django_extras.views for use
    'permission', 'authorization' and 'throttle' classes based on the DRF settings. Special thanks to
    [@jacobh](https://github.com/jacobh) for this
    [comment](https://github.com/graphql-python/graphene/issues/249#issuecomment-300068390)

#### v0.1.0-alpha3:
    1.  Fixed bug on subscriptions when not specified any field in "data" parameter to bean return on notification
    message.

#### v0.1.0-alpha2:
    1.  Fixed bug when subscribing to a given action (create, update or delete).
    2.  Added intuitive and simple web tool to test notifications of graphene-django-extras subscription.

#### v0.1.0-alpha1:
    1.  Added support to multiselect choices values for models.CharField with choices attribute,
    on queries and mutations. Example: Integration with django-multiselectfield package.
    2.  Added support to GenericForeignKey and GenericRelation fields, on queries and mutations.
    3.  Added first approach to support Subscriptions with Channels, with subscribe and unsubscribe operations.
    Using channels-api package.
    4.  Fixed minors bugs.

#### v0.0.4:
    1. Fix error on DateType encode.

#### v0.0.3:
    1. Implement custom implementation of DateType for use converter and avoid error on Serializer Mutation.

#### v0.0.2:
    1. Changed dependency of DRF to 3.6.4 on setup.py file, to avoid an import error produced by some changes in
    new version of DRF=3.7.0 and because DRF 3.7.0 dropped support to Django versions < 1.10.

#### v0.0.1:
    1. Fixed bug on DjangoInputObjectType class that refer to unused interface attribute.
    2. Added support to create nested objects like in
    [DRF](http://www.django-rest-framework.org/api-guide/serializers/#writable-nested-representations),
    it's valid to SerializerMutation and DjangoInputObjectType, only is necessary to specify nested_fields=True
    on its Meta class definition.
    3. Added support to show, only in mutations types to create objects and with debug=True on settings,
    inputs autocomplete ordered by required fields first.
    4. Fixed others minors bugs.

#### v0.0.1-rc.2:
    1. Make queries pagination configuration is more friendly.

#### v0.0.1-rc.1:
    1. Fixed a bug with input fields in the converter function.

#### v0.0.1-beta.10:
    1. Fixed bug in the queryset_factory function because it did not always return a queryset.

#### v0.0.1-beta.9:
    1. Remove hard dependence with psycopg2 module.
    2. Fixed bug that prevented use queries with fragments.
    3. Fixed bug relating to custom django_filters module and ordering fields.

#### v0.0.1-beta.6:
    1. Optimizing imports, fix some minors bugs and working on performance.

#### v0.0.1-beta.5:
    1. Repair conflict on converter.py, by the use of get_related_model function with: OneToOneRel,
    ManyToManyRel and ManyToOneRel.

#### v0.0.1-beta.4:
    1. First commit.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/eamigo86/graphene-django-extras",
    "name": "graphene-django-extras",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7,<4.0",
    "maintainer_email": "",
    "keywords": "api,graphql,protocol,graphene,django",
    "author": "Ernesto Perez Amigo",
    "author_email": "eamigop86@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/07/54/b3e8c32bc24561e803f305640a74a8089e5dee7cb94d3bf2a55a30f2587e/graphene_django_extras-1.0.0.tar.gz",
    "platform": null,
    "description": "\n---\n\n# Graphene-Django-Extras\n![Travis (.org) branch](https://img.shields.io/travis/eamigo86/graphene-django-extras/master)\n![Codecov](https://img.shields.io/codecov/c/github/eamigo86/graphene-django-extras)\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/graphene-django-extras)\n![PyPI](https://img.shields.io/pypi/v/graphene-django-extras?color=blue)\n![PyPI - License](https://img.shields.io/pypi/l/graphene-django-extras)\n![PyPI - Downloads](https://img.shields.io/pypi/dm/graphene-django-extras?style=flat)\n![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)\n\nThis package adds some extra functionalities to graphene-django to facilitate the graphql use without Relay:\n  1. Allow pagination and filtering on Queries.\n  2. Allow defining DjangoRestFramework serializers based on Mutations.\n  3. Allow using Directives on Queries and Fragments.\n\n**NOTE:** Subscription support was moved to [graphene-django-subscriptions](https://github.com/eamigo86/graphene-django-subscriptions).\n\n## Installation\n\nFor installing graphene-django-extras, just run this command in your shell:\n\n```\npip install graphene-django-extras\n```\n\n## Documentation:\n\n### Extra functionalities:\n **Fields:**\n  1.  DjangoObjectField\n  2.  DjangoFilterListField\n  3.  DjangoFilterPaginateListField\n  4.  DjangoListObjectField (*Recommended for Queries definition*)\n\n **Mutations:**\n  1.  DjangoSerializerMutation (*Recommended for Mutations definition*)\n\n **Types:**\n  1.  DjangoListObjectType  (*Recommended for Types definition*)\n  2.  DjangoInputObjectType\n  3.  DjangoSerializerType  (*Recommended for quick queries and mutations definitions*)\n\n **Paginations:**\n  1.  LimitOffsetGraphqlPagination\n  2.  PageGraphqlPagination\n\n\n### Queries and Mutations examples:\n\nThis is a basic example of graphene-django-extras package use. You can configure global params\nfor DjangoListObjectType classes pagination definitions on settings.py like this:\n\n```python\n    GRAPHENE_DJANGO_EXTRAS = {\n        'DEFAULT_PAGINATION_CLASS': 'graphene_django_extras.paginations.LimitOffsetGraphqlPagination',\n        'DEFAULT_PAGE_SIZE': 20,\n        'MAX_PAGE_SIZE': 50,\n        'CACHE_ACTIVE': True,\n        'CACHE_TIMEOUT': 300    # seconds\n    }\n```\n\n#### 1- Types Definition:\n\n```python\nfrom django.contrib.auth.models import User\nfrom graphene_django_extras import DjangoListObjectType, DjangoSerializerType, DjangoObjectType\nfrom graphene_django_extras.paginations import LimitOffsetGraphqlPagination\n\nfrom .serializers import UserSerializer\n\n\nclass UserType(DjangoObjectType):\n    class Meta:\n        model = User\n        description = \" Type definition for a single user \"\n        filter_fields = {\n            \"id\": (\"exact\", ),\n            \"first_name\": (\"icontains\", \"iexact\"),\n            \"last_name\": (\"icontains\", \"iexact\"),\n            \"username\": (\"icontains\", \"iexact\"),\n            \"email\": (\"icontains\", \"iexact\"),\n            \"is_staff\": (\"exact\", ),\n        }\n\n\nclass UserListType(DjangoListObjectType):\n    class Meta:\n        description = \" Type definition for user list \"\n        model = User\n        pagination = LimitOffsetGraphqlPagination(default_limit=25, ordering=\"-username\") # ordering can be: string, tuple or list\n\n\nclass UserModelType(DjangoSerializerType):\n    \"\"\" With this type definition it't necessary a mutation definition for user's model \"\"\"\n\n    class Meta:\n        description = \" User model type definition \"\n        serializer_class = UserSerializer\n        pagination = LimitOffsetGraphqlPagination(default_limit=25, ordering=\"-username\") # ordering can be: string, tuple or list\n        filter_fields = {\n            \"id\": (\"exact\", ),\n            \"first_name\": (\"icontains\", \"iexact\"),\n            \"last_name\": (\"icontains\", \"iexact\"),\n            \"username\": (\"icontains\", \"iexact\"),\n            \"email\": (\"icontains\", \"iexact\"),\n            \"is_staff\": (\"exact\", ),\n        }\n```\n\n#### 2- You can to define InputTypes for use on mutations:\n\n```python\nfrom graphene_django_extras import DjangoInputObjectType\n\n\nclass UserInput(DjangoInputObjectType):\n    class Meta:\n        description = \" User InputType definition to use as input on an Arguments class on traditional Mutations \"\n        model = User\n```\n\n#### 3- You can define traditional mutations that use InputTypes or Mutations based on DRF serializers:\n\n```python\nimport graphene\nfrom graphene_django_extras import DjangoSerializerMutation\n\nfrom .serializers import UserSerializer\nfrom .types import UserType\nfrom .input_types import UserInputType\n\n\nclass UserSerializerMutation(DjangoSerializerMutation):\n    \"\"\"\n        DjangoSerializerMutation auto implement Create, Delete and Update functions\n    \"\"\"\n    class Meta:\n        description = \" DRF serializer based Mutation for Users \"\n        serializer_class = UserSerializer\n\n\nclass UserMutation(graphene.Mutation):\n    \"\"\"\n         On traditional mutation classes definition you must implement the mutate function\n\n    \"\"\"\n\n    user = graphene.Field(UserType, required=False)\n\n    class Arguments:\n        new_user = graphene.Argument(UserInput)\n\n    class Meta:\n        description = \" Graphene traditional mutation for Users \"\n\n    @classmethod\n    def mutate(cls, root, info, *args, **kwargs):\n        ...\n```\n\n#### 4- Defining the Schema file:\n\n```python\nimport graphene\nfrom graphene_django_extras import DjangoObjectField, DjangoListObjectField, DjangoFilterPaginateListField,\nDjangoFilterListField, LimitOffsetGraphqlPagination\nfrom .types import UserType, UserListType, UserModelType\nfrom .mutations import UserMutation, UserSerializerMutation\n\n\nclass Queries(graphene.ObjectType):\n    # Possible User list queries definitions\n    users = DjangoListObjectField(UserListType, description='All Users query')\n    users1 = DjangoFilterPaginateListField(UserType, pagination=LimitOffsetGraphqlPagination())\n    users2 = DjangoFilterListField(UserType)\n    users3 = DjangoListObjectField(UserListType, filterset_class=UserFilter, description='All Users query')\n\n    # Defining a query for a single user\n    # The DjangoObjectField have a ID type input field, that allow filter by id and is't necessary to define resolve function\n    user = DjangoObjectField(UserType, description='Single User query')\n\n    # Another way to define a query to single user\n    user1 = UserListType.RetrieveField(description='User List with pagination and filtering')\n\n    # Exist two ways to define single or list user queries with DjangoSerializerType\n    user_retrieve1, user_list1 = UserModelType.QueryFields(\n        description='Some description message for both queries',\n        deprecation_reason='Some deprecation message for both queries'\n    )\n    user_retrieve2 = UserModelType.RetrieveField(\n        description='Some description message for retrieve query',\n        deprecation_reason='Some deprecation message for retrieve query'\n    )\n    user_list2 = UserModelType.ListField(\n        description='Some description message for list query',\n        deprecation_reason='Some deprecation message for list query'\n    )\n\nclass Mutations(graphene.ObjectType):\n    user_create = UserSerializerMutation.CreateField(deprecation_reason='Some one deprecation message')\n    user_delete = UserSerializerMutation.DeleteField()\n    user_update = UserSerializerMutation.UpdateField()\n\n    # Exist two ways to define mutations with DjangoSerializerType\n    user_create1, user_delete1, user_update1 = UserModelType.MutationFields(\n        description='Some description message for create, delete and update mutations',\n        deprecation_reason='Some deprecation message for create, delete and update mutations'\n    )\n\n    user_create2 = UserModelType.CreateField(description='Description message for create')\n    user_delete2 = UserModelType.DeleteField(description='Description message for delete')\n    user_update2 = UserModelType.UpdateField(description='Description message for update')\n\n    traditional_user_mutation = UserMutation.Field()\n```\n\n#### 5- Directives settings:\nFor use Directives you must follow two simple steps:\n1. You must add **'graphene_django_extras.ExtraGraphQLDirectiveMiddleware'** to your GRAPHENE dict\nconfig on your settings.py:\n\n```python\n# settings.py\n\nGRAPHENE = {\n    'SCHEMA_INDENT': 4,\n    'MIDDLEWARE': [\n        'graphene_django_extras.ExtraGraphQLDirectiveMiddleware'\n    ]\n}\n```\n\n2. You must add the *directives* param with your custom directives to your schema definition. This module comes with\nsome common directives for you, these directives allow to you format strings, numbers, lists, and dates (optional), and\nyou can load like this:\n\n```python\n# schema.py\nfrom graphene_django_extras import all_directives\n\nschema = graphene.Schema(\n    query=RootQuery,\n    mutation=RootMutation,\n    directives=all_directives\n)\n```\n**NOTE**: Date directive depends on *dateutil* module, so if you do not have installed it, this directive will not be\navailable. You can install *dateutil* module manually:\n```\npip install python-dateutil\n```\nor like this:\n```\npip install graphene-django-extras[date]\n```\nThat's all !!!\n\n\n#### 6- Complete Directive list:\n\n##### FOR NUMBERS:\n1. **FloorGraphQLDirective**: Floors value. Supports both String and Float fields.\n2. **CeilGraphQLDirective**: Ceils value. Supports both String and Float fields.\n\n##### FOR LIST:\n1. **ShuffleGraphQLDirective**: Shuffle the list in place.\n2. **SampleGraphQLDirective**: Take a 'k' int argument and return a k length list of unique elements chosen from the\ntaken list\n\n##### FOR DATE:\n1. **DateGraphQLDirective**: Take a optional 'format' string argument and format the date from resolving the field by\ndateutil module with the 'format' format. Default format is: 'DD MMM YYYY HH:mm:SS' equivalent to\n'%d %b %Y %H:%M:%S' python format.\n\n##### FOR STRING:\n1. **DefaultGraphQLDirective**: Take a 'to' string argument. Default to given value if None or \"\"\n2. **Base64GraphQLDirective**: Take a optional (\"encode\" or \"decode\") 'op' string argument(default='encode').\nEncode or decode the string taken.\n3. **NumberGraphQLDirective**: Take a 'as' string argument. String formatting like a specify Python number formatting.\n4. **CurrencyGraphQLDirective**: Take a optional 'symbol' string argument(default=\"$\").\nPrepend the *symbol* argument to taken string and format it like a currency.\n5. **LowercaseGraphQLDirective**: Lowercase the taken string.\n6. **UppercaseGraphQLDirective**: Uppercase the taken string.\n7. **CapitalizeGraphQLDirective**: Return the taken string with its first character capitalized and the rest lowered.\n8. **CamelCaseGraphQLDirective**: CamelCase the taken string.\n9. **SnakeCaseGraphQLDirective**: SnakeCase the taken string.\n10. **KebabCaseGraphQLDirective**: SnakeCase the taken string.\n11. **SwapCaseGraphQLDirective**: Return the taken string with uppercase characters converted to lowercase and vice\nversa.\n12. **StripGraphQLDirective**: Take a optional 'chars' string argument(default=\" \").\nReturn the taken string with the leading and trailing characters removed. The 'chars' argument is not a prefix or\nsuffix; rather, all combinations of its values are stripped.\n13. **TitleCaseGraphQLDirective**: Return the taken string title-cased, where words start with an uppercase character\nand the remaining characters are lowercase.\n14. **CenterGraphQLDirective**: Take a 'width' string argument and a optional 'fillchar' string argument(default=\" \").\nReturn the taken string centered with the 'width' argument as new length. Padding is done using the specified\n'fillchar' argument. The original string is returned if 'width' argument is less than or equal to taken string\nlength.\n15. **ReplaceGraphQLDirective**: Take two strings arguments 'old' and 'new', and a optional integer argument\n'count'.\nReturn the taken string with all occurrences of substring 'old' argument replaced by 'new' argument value.\nIf the optional argument 'count' is given, only the first 'count' occurrences are replaced.\n\n\n#### 7- Queries's examples:\n```js\n{\n  allUsers(username_Icontains:\"john\"){\n    results(limit:5, offset:5){\n      id\n      username\n      firstName\n      lastName\n    }\n    totalCount\n  }\n\n  allUsers1(lastName_Iexact:\"Doe\", limit:5, offset:0){\n    id\n    username\n    firstName\n    lastName\n  }\n\n  allUsers2(firstName_Icontains: \"J\"){\n    id\n    username\n    firstName\n    lastName\n  }\n\n  user(id:2){\n    id\n    username\n    firstName\n  }\n\n  user1(id:2){\n    id\n    username\n    firstName\n  }\n}\n```\n\n#### 8- Mutations's examples:\n\n```js\nmutation{\n  userCreate(newUser:{username:\"test\", password:\"test*123\"}){\n    user{\n      id\n      username\n      firstName\n      lastName\n    }\n    ok\n    errors{\n      field\n      messages\n    }\n  }\n\n  userDelete(id:1){\n    ok\n    errors{\n      field\n      messages\n    }\n  }\n\n  userUpdate(newUser:{id:1, username:\"John\"}){\n    user{\n      id\n      username\n    }\n    ok\n    errors{\n      field\n      messages\n    }\n  }\n}\n```\n\n#### 9- Directives's examples:\nLet's suppose that we have this query:\n```js\nquery{\n    allUsers{\n        result{\n            id\n            firstName\n            lastName\n            dateJoined\n            lastLogin\n        }\n    }\n}\n```\nAnd return this data:\n```js\n{\n  \"data\": {\n    \"allUsers\": {\n      \"results\": [\n        {\n            \"id\": \"1\",\n            \"firstName\": \"JOHN\",\n            \"lastName\": \"\",\n            \"dateJoined\": \"2017-06-20 09:40:30\",\n            \"lastLogin\": \"2017-08-05 21:05:02\"\n        },\n        {\n            \"id\": \"2\",\n            \"firstName\": \"Golden\",\n            \"lastName\": \"GATE\",\n            \"dateJoined\": \"2017-01-02 20:36:45\",\n            \"lastLogin\": \"2017-06-20 10:15:31\"\n        },\n        {\n            \"id\": \"3\",\n            \"firstName\": \"Nike\",\n            \"lastName\": \"just do it!\",\n            \"dateJoined\": \"2017-08-30 16:05:20\",\n            \"lastLogin\": \"2017-12-05 09:23:09\"\n        }\n      ]\n    }\n  }\n}\n```\nAs we see, some data it's missing or just not have the format that we like it, so let's go to format the output data\nthat we desired:\n```js\nquery{\n    allUsers{\n        result{\n            id\n            firstName @capitalize\n            lastName @default(to: \"Doe\") @title_case\n            dateJoined @date(format: \"DD MMM YYYY HH:mm:SS\")\n            lastLogin @date(format: \"time ago\")\n        }\n    }\n}\n```\nAnd we get this output data:\n```js\n{\n  \"data\": {\n    \"allUsers\": {\n      \"results\": [\n        {\n            \"id\": \"1\",\n            \"firstName\": \"John\",\n            \"lastName\": \"Doe\",\n            \"dateJoined\": \"20 Jun 2017 09:40:30\",\n            \"lastLogin\": \"4 months, 12 days, 15 hours, 27 minutes and 58 seconds ago\"\n        },\n        {\n            \"id\": \"2\",\n            \"firstName\": \"Golden\",\n            \"lastName\": \"Gate\",\n            \"dateJoined\": \"02 Jan 2017 20:36:45\",\n            \"lastLogin\": \"5 months, 28 days, 2 hours, 17 minutes and 53 seconds ago\"\n        },\n        {\n            \"id\": \"3\",\n            \"firstName\": \"Nike\",\n            \"lastName\": \"Just Do It!\",\n            \"dateJoined\": \"30 Aug 2017 16:05:20\",\n            \"lastLogin\": \"13 days, 3 hours, 10 minutes and 31 seconds ago\"\n        }\n      ]\n    }\n  }\n}\n```\nAs we see, the directives are an easy way to format output data on queries, and it's can be put together like a chain.\n\n**List of possible date's tokens**:\n\"YYYY\", \"YY\", \"WW\", \"W\", \"DD\", \"DDDD\", \"d\", \"ddd\", \"dddd\", \"MM\", \"MMM\", \"MMMM\", \"HH\", \"hh\", \"mm\", \"ss\", \"A\", \"ZZ\", \"z\".\n\nYou can use this shortcuts too:\n\n1. \"time ago\"\n2. \"iso\": \"YYYY-MMM-DDTHH:mm:ss\"\n3. \"js\" or \"javascript\": \"ddd MMM DD YYYY HH:mm:ss\"\n\n\n## Change Log:\n\n#### v1.0.0:\n    1. Added support to Django 4.x\n    2. Removed support for Django versions < 3.2\n\n#### v0.5.1:\n    1. Update dependencies\n\n#### v0.5.0:\n    1. Upgrade to graphene v3\n\n#### v0.4.8:\n    1. Upgrade graphene-django dependency to version == 2.6.0.\n\n#### v0.4.6:\n    1. Upgrade graphql-core dependency to version >= 2.2.1.\n    2. Upgrade graphene dependency to version >= 2.1.8.\n    3. Upgrade graphene-django dependency to version >= 2.5.0.\n    4. Upgrade django-filter dependency to version >= 2.2.0.\n    5. Fixed bug 'DjangoSerializerOptions' object has no attribute 'interfaces' after update to graphene==2.1.8.\n    6. The tests were refactored and added some extra tests for DjangoSerializerType.\n\n#### v0.4.5:\n    1. Fixed compatibilities issues to use graphene-django>=2.3.2.\n    2. Improved code quality and use Black code format.\n    3. Fixed minor bug with \"time ago\" date directive.\n\n#### v0.3.7:\n    1. Improved DjangoListType and DjangoObjectType to share the filterset_class between the two class.\n\n#### v0.3.6:\n    1. Improve DjangoSerializerMutation resolvers.\n\n#### v0.3.5:\n    1. Fixed minor bug on ExtraGraphQLDirectiveMiddleware.\n    2. Fixed error with DRF 3.8 Compatibility.\n    3. Updated List's Fields to pass info.context to filterset as request, this allow filtering by request data.\n    4. Added new feature to ordering paginated queries.\n\n#### v0.3.4-alpha2:\n    1. Fixed minor bug on DjangoListObjectType.\n\n#### v0.3.4-alpha1:\n    1. Added filterset_class to the listing types as default filter.\n    2. Changed getOne by RetrieveField on DjangoListObjectType.\n\n####  v0.3.3:\n    1. Added filterset_class to DjangoObjectType.\n    2. Fixed minor bug on factory_types function.\n\n####  v0.3.3-alpha1:\n    1. Fixed minor bug on *queryset_factory* function.\n\n#### v0.3.2:\n    1. Updated Date directive format function for better string format combinations.\n    2. Updated custom Time, Date and DateTime base types to be used with Date directive.\n    3. Fixed bug with caching Introspection queries on ExtraGraphQLView.\n\n#### v0.3.1:\n    1. Fixed bug with default Date directive format.\n\n#### v0.3.0:\n    1. Added Binary graphql type. A BinaryArray is used to convert a Django BinaryField to the string form.\n    2. Added 'CACHE_ACTIVE' and 'CACHE_TIMEOUT' config options to GRAPHENE_DJANGO_EXTRAS settings for activate cache and\n     define a expire time. Default values are: CACHE_ACTIVE=False, CACHE_TIMEOUT=300 (seconds). Only available for\n     Queries.\n    3. Updated Date directive for use with Django TimeField, DateField, and DateTimeField.\n    4. Updated ExtraGraphQLView and AuthenticatedGraphQLView to allow use subscription requests on graphene-django >=2.0\n    5. Updated setup dependence to graphene-django>=2.0.\n\n#### v0.2.2:\n    1. Fixed performance bug on some queries when request nested ManyToMany fields.\n\n#### v0.2.1:\n    1. Fixed bug with default PaginationClass and DjangoFilterPaginateListField.\n\n#### v0.2.0:\n    1. Added some useful directives to use on queries and fragments.\n    2. Fixed error on DjangoFilterPaginateListField resolve function.\n\n#### v0.1.6:\n    1. Fixed bug on create and update function on serializer mutation.\n\n#### v0.1.3:\n    1. Fixed minors  bugs.\n\n#### v0.1.2:\n    1. Added ok field and errors field to DjangoSerializerType like on DjangoSerializerMutation.\n    2. Added possibility of filtering in those queries fields that return a list of objects.\n    3. Updated DRF compatibility.\n    4. Fixed bug with filters when use global DEFAULT_PAGINATION_CLASS.\n\n#### v0.1.1:\n    1. Fixed error with JSONField reference on Django==1.8.x installations.\n\n#### v0.1.0:\n    1. Added DjangoSerializerType for quick Django's models types definition (See documentation).\n    2. Moved support for Subscriptions to graphene-django-subscriptions packages for\n    incompatibility with graphene-django>=2.0.\n    3. Fixed bug on DjangoFilterPaginateListField's pagination.\n\n#### v0.1.0-alpha12:\n    1. Added new settings param: MAX_PAGE_SIZE, to use on GRAPHENE_DJANGO_EXTRAS\n    configuration dict for better customize DjangoListObjectType's pagination.\n    2. Added support to Django's field: GenericRel.\n    3. Improve model's fields calculation for to add all possible related and reverse fields.\n    4. Improved documentation translation.\n\n#### v0.1.0-alpha11:\n    1. Improved ordering for showed fields on graphqli's IDE.\n    2. Added better descriptions for auto generated fields.\n\n#### v0.1.0-alpha10:\n    1. Improve converter.py file to avoid create field for auto generate OneToOneField\n    product of an inheritance.\n    2. Fixed bug in Emun generation for fields with choices of model inheritance child.\n\n#### v0.1.0-alpha9:\n    1. Fixed bug on GenericType and GenericInputType generations for\n    Queries list Type and Mutations.\n\n#### v0.1.0-alpha6:\n    1. Fixed with exclude fields and converter function.\n\n#### v0.1.0-alpha5:\n    1. Updated dependencies to graphene-django>=2.0.\n    2. Fixed minor bugs on queryset_builder performance.\n\n#### v0.1.0-alpha4:\n    1.  Add queryset options to DjangoListObjectType Meta class for specify wanted model queryset.\n    2.  Add AuthenticatedGraphQLView on graphene_django_extras.views for use\n    'permission', 'authorization' and 'throttle' classes based on the DRF settings. Special thanks to\n    [@jacobh](https://github.com/jacobh) for this\n    [comment](https://github.com/graphql-python/graphene/issues/249#issuecomment-300068390)\n\n#### v0.1.0-alpha3:\n    1.  Fixed bug on subscriptions when not specified any field in \"data\" parameter to bean return on notification\n    message.\n\n#### v0.1.0-alpha2:\n    1.  Fixed bug when subscribing to a given action (create, update or delete).\n    2.  Added intuitive and simple web tool to test notifications of graphene-django-extras subscription.\n\n#### v0.1.0-alpha1:\n    1.  Added support to multiselect choices values for models.CharField with choices attribute,\n    on queries and mutations. Example: Integration with django-multiselectfield package.\n    2.  Added support to GenericForeignKey and GenericRelation fields, on queries and mutations.\n    3.  Added first approach to support Subscriptions with Channels, with subscribe and unsubscribe operations.\n    Using channels-api package.\n    4.  Fixed minors bugs.\n\n#### v0.0.4:\n    1. Fix error on DateType encode.\n\n#### v0.0.3:\n    1. Implement custom implementation of DateType for use converter and avoid error on Serializer Mutation.\n\n#### v0.0.2:\n    1. Changed dependency of DRF to 3.6.4 on setup.py file, to avoid an import error produced by some changes in\n    new version of DRF=3.7.0 and because DRF 3.7.0 dropped support to Django versions < 1.10.\n\n#### v0.0.1:\n    1. Fixed bug on DjangoInputObjectType class that refer to unused interface attribute.\n    2. Added support to create nested objects like in\n    [DRF](http://www.django-rest-framework.org/api-guide/serializers/#writable-nested-representations),\n    it's valid to SerializerMutation and DjangoInputObjectType, only is necessary to specify nested_fields=True\n    on its Meta class definition.\n    3. Added support to show, only in mutations types to create objects and with debug=True on settings,\n    inputs autocomplete ordered by required fields first.\n    4. Fixed others minors bugs.\n\n#### v0.0.1-rc.2:\n    1. Make queries pagination configuration is more friendly.\n\n#### v0.0.1-rc.1:\n    1. Fixed a bug with input fields in the converter function.\n\n#### v0.0.1-beta.10:\n    1. Fixed bug in the queryset_factory function because it did not always return a queryset.\n\n#### v0.0.1-beta.9:\n    1. Remove hard dependence with psycopg2 module.\n    2. Fixed bug that prevented use queries with fragments.\n    3. Fixed bug relating to custom django_filters module and ordering fields.\n\n#### v0.0.1-beta.6:\n    1. Optimizing imports, fix some minors bugs and working on performance.\n\n#### v0.0.1-beta.5:\n    1. Repair conflict on converter.py, by the use of get_related_model function with: OneToOneRel,\n    ManyToManyRel and ManyToOneRel.\n\n#### v0.0.1-beta.4:\n    1. First commit.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "This library add some extra funcionalities to graphene-django to facilitate the graphql use without Relay, allow paginations and filtering integration and add some extra directives",
    "version": "1.0.0",
    "split_keywords": [
        "api",
        "graphql",
        "protocol",
        "graphene",
        "django"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "add742df93d6f8d7f1173b0446f3ec71e06a69a2590b7017aa07099432207560",
                "md5": "a893e423b7eafab128f6debc525c8f8a",
                "sha256": "1059965b8b71f09da6f869f3407062c9b1aac2a69aef2c9504571e5b1f8f8621"
            },
            "downloads": -1,
            "filename": "graphene_django_extras-1.0.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "a893e423b7eafab128f6debc525c8f8a",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7,<4.0",
            "size": 45122,
            "upload_time": "2023-01-23T09:26:28",
            "upload_time_iso_8601": "2023-01-23T09:26:28.339218Z",
            "url": "https://files.pythonhosted.org/packages/ad/d7/42df93d6f8d7f1173b0446f3ec71e06a69a2590b7017aa07099432207560/graphene_django_extras-1.0.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "0754b3e8c32bc24561e803f305640a74a8089e5dee7cb94d3bf2a55a30f2587e",
                "md5": "7eda147f6d9890a07e02a78e31657915",
                "sha256": "c723c422f3c015acbbbf461d08339e5eca7bf8f2bee974cfa2141069074cbc4b"
            },
            "downloads": -1,
            "filename": "graphene_django_extras-1.0.0.tar.gz",
            "has_sig": false,
            "md5_digest": "7eda147f6d9890a07e02a78e31657915",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7,<4.0",
            "size": 44548,
            "upload_time": "2023-01-23T09:26:30",
            "upload_time_iso_8601": "2023-01-23T09:26:30.747693Z",
            "url": "https://files.pythonhosted.org/packages/07/54/b3e8c32bc24561e803f305640a74a8089e5dee7cb94d3bf2a55a30f2587e/graphene_django_extras-1.0.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-01-23 09:26:30",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "eamigo86",
    "github_project": "graphene-django-extras",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "graphene-django-extras"
}
        
Elapsed time: 0.03207s