Skip to content

Commit

Permalink
1. Added Binary graphql type. A BinaryArray is used to convert a Djan…
Browse files Browse the repository at this point in the history
…go 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.
  • Loading branch information
Ernesto Perez Amigo committed Jan 5, 2018
1 parent 013be3b commit 428b6da
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 81 deletions.
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ This package add some extra functionalities to graphene-django to facilitate the
2. Allows to define DjangoRestFramework serializers based Mutations.
3. Allows use Directives on Queries and Fragments.

**NOTE:** Subscription support was moved to [graphene-django-subscriptions](https://github.com/eamigo86/graphene-django-subscriptions) due incompatibility with subscriptions on graphene-django>=2.0
**NOTE:** Subscription support was moved to [graphene-django-subscriptions](https://github
.com/eamigo86/graphene-django-subscriptions).

## Installation

Expand Down Expand Up @@ -52,6 +53,8 @@ for DjangoListObjectType classes pagination definitions on settings.py like this
'DEFAULT_PAGINATION_CLASS': 'graphene_django_extras.paginations.LimitOffsetGraphqlPagination',
'DEFAULT_PAGE_SIZE': 20,
'MAX_PAGE_SIZE': 50,
'CACHE_ACTIVE': True,
'CACHE_TIMEOUT': 300 # seconds
}
```

Expand Down Expand Up @@ -468,9 +471,6 @@ And we get this output data:
```
As we see, the directives is a easy way to format output data on queries, and it's can be put together like a chain.

**IMPORTANT NOTE**: The *date* directive only work with datetime returned as String Type and take a string of tokens,
this tokens are the common of JavaScript date format.

**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".

Expand All @@ -483,6 +483,18 @@ You can use this shortcuts too:

## Change Log:

#### 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.

Expand Down
21 changes: 17 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This package add some extra functionalities to **graphene-django** to facilitate
2. Allows to define DjangoRestFramework serializers based Mutations.
3. Allows use Directives on Queries and Fragments.

**NOTE:** Subscription support was moved to `graphene-django-subscriptions <https://github.com/eamigo86/graphene-django-subscriptions>`_ due incompatibility with subscriptions on graphene-django>=2.0
**NOTE:** Subscription support was moved to `graphene-django-subscriptions <https://github.com/eamigo86/graphene-django-subscriptions>`_

Installation:
-------------
Expand Down Expand Up @@ -55,6 +55,8 @@ DjangoListObjectType classes pagination definitions on settings.py like this:
'DEFAULT_PAGINATION_CLASS': 'graphene_django_extras.paginations.LimitOffsetGraphqlPagination',
'DEFAULT_PAGE_SIZE': 20,
'MAX_PAGE_SIZE': 50,
'CACHE_ACTIVE': True,
'CACHE_TIMEOUT': 300 # seconds
}
********************
Expand Down Expand Up @@ -510,9 +512,6 @@ And we get this output data:
As we see, the directives is a easy way to format output data on queries, and it's can be put together like a chain.

**IMPORTANT NOTE**: The *date* directive only work with datetime returned as Graphene String Type not with normal
Graphene DateTime, Time or Date Types and take a string of tokens, this tokens are the common of JavaScript date format.

**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".

Expand All @@ -526,6 +525,20 @@ You can use this shortcuts too:
Change Log:
-----------

*******
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 queries result and define a expire time. Default values are: CACHE_ACTIVE=False, CACHE_TIMEOUT=300 (5 minutes).
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:
*******
Expand Down
2 changes: 1 addition & 1 deletion graphene_django_extras/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from .paginations import LimitOffsetGraphqlPagination, PageGraphqlPagination, CursorGraphqlPagination
from .types import DjangoObjectType, DjangoInputObjectType, DjangoListObjectType, DjangoSerializerType

VERSION = (0, 2, 2, 'final', '')
VERSION = (0, 3, 0, 'final', '')

__version__ = get_version(VERSION)

Expand Down
150 changes: 115 additions & 35 deletions graphene_django_extras/base_types.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import

import binascii
import datetime
import graphene

from graphene import Scalar
import graphene
from graphene.utils.str_converters import to_camel_case
from graphql.language import ast

Expand All @@ -17,39 +17,6 @@
)


class Date(Scalar):
'''
The `Date` scalar type represents a Date
value as specified by
[iso8601](https://en.wikipedia.org/wiki/ISO_8601).
'''
epoch_time = '00:00:00'

@staticmethod
def serialize(date):
if isinstance(date, datetime.datetime):
date = date.date()

assert isinstance(date, datetime.date), (
'Received not compatible date "{}"'.format(repr(date))
)
return date.isoformat()

@classmethod
def parse_literal(cls, node):
if isinstance(node, ast.StringValue):
return cls.parse_value(node.value)

@classmethod
def parse_value1(cls, value):
dt = iso8601.parse_date('{}T{}'.format(value, cls.epoch_time))
return datetime.date(dt.year, dt.month, dt.day)

@staticmethod
def parse_value(value):
return iso8601.parse_date(value).date()


def object_type_factory(_type, new_model, new_name=None, new_only_fields=(), new_exclude_fields=(),
new_filter_fields=None, new_registry=None, new_skip_registry=False):

Expand Down Expand Up @@ -144,3 +111,116 @@ class GenericForeignKeyInputType(graphene.InputObjectType):

class Meta:
description = ' Auto generated InputType for a model\'s GenericForeignKey field '


# ************************************************ #
# ************** CUSTOM BASE TYPES *************** #
# ************************************************ #
class CustomDate(object):

def __init__(self, date):
self.date_str = date


class Binary(graphene.Scalar):
"""
BinaryArray is used to convert a Django BinaryField to the string form
"""
@staticmethod
def binary_to_string(value):
return binascii.hexlify(value).decode("utf-8")

serialize = binary_to_string
parse_value = binary_to_string

@classmethod
def parse_literal(cls, node):
if isinstance(node, ast.StringValue):
return cls.binary_to_string(node.value)


class Time(graphene.Scalar):
"""
The `Time` scalar type represents a Time value as
specified by
[iso8601](https://en.wikipedia.org/wiki/ISO_8601).
"""
epoch_date = '1970-01-01'

@staticmethod
def serialize(time):
if isinstance(time, CustomDate):
return time.date_str

assert isinstance(time, datetime.time), (
'Received not compatible time "{}"'.format(repr(time))
)
return time.isoformat()

@classmethod
def parse_literal(cls, node):
if isinstance(node, ast.StringValue):
return cls.parse_value(node.value)

@classmethod
def parse_value(cls, value):
dt = iso8601.parse_date('{}T{}'.format(cls.epoch_date, value))
return datetime.time(dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo)


class Date(graphene.Scalar):
"""
The `Date` scalar type represents a Date
value as specified by
[iso8601](https://en.wikipedia.org/wiki/ISO_8601).
"""
epoch_time = '00:00:00'

@staticmethod
def serialize(date):
if isinstance(date, CustomDate):
return date.date_str

if isinstance(date, datetime.datetime):
date = date.date()

assert isinstance(date, datetime.date), (
'Received not compatible date "{}"'.format(repr(date))
)
return date.isoformat()

@classmethod
def parse_literal(cls, node):
if isinstance(node, ast.StringValue):
return cls.parse_value(node.value)

@staticmethod
def parse_value(value):
return iso8601.parse_date(value).date()


class DateTime(graphene.Scalar):
"""
The `DateTime` scalar type represents a DateTime
value as specified by
[iso8601](https://en.wikipedia.org/wiki/ISO_8601).
"""

@staticmethod
def serialize(dt):
if isinstance(dt, CustomDate):
return dt.date_str

assert isinstance(dt, (datetime.datetime, datetime.date)), (
'Received not compatible datetime "{}"'.format(repr(dt))
)
return dt.isoformat()

@classmethod
def parse_literal(cls, node):
if isinstance(node, ast.StringValue):
return cls.parse_value(node.value)

@staticmethod
def parse_value(value):
return iso8601.parse_date(value)
19 changes: 12 additions & 7 deletions graphene_django_extras/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,20 @@
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation, GenericRel
from django.db import models
from django.utils.encoding import force_text
from graphene import (Field, ID, Boolean, Dynamic, Enum, Float, Int, List, NonNull, String, UUID)
from graphene.types.datetime import DateTime, Time
from graphene import (
Field, ID, Boolean, Dynamic, Enum, Float, Int, List, NonNull, String, UUID
)
from graphene.types.json import JSONString
from graphene.utils.str_converters import to_camel_case, to_const
from graphene_django.compat import ArrayField, HStoreField, RangeField, JSONField
from graphene_django.fields import DjangoListField
from graphene_django.utils import import_single_dispatch

from .base_types import GenericForeignKeyType, GenericForeignKeyInputType
from .base_types import (
GenericForeignKeyType, GenericForeignKeyInputType, DateTime, Time, Date, Binary
)
from .fields import DjangoFilterListField
from .utils import is_required, get_model_fields, get_related_model
try:
from graphene import Date
except ImportError:
from .base_types import Date

singledispatch = import_single_dispatch()

Expand Down Expand Up @@ -179,6 +178,12 @@ def convert_field_to_nullboolean(field, registry=None, input_flag=None, nested_f
required=is_required(field) and input_flag == 'create')


@convert_django_field.register(models.BinaryField)
def convert_binary_to_string(field, registry=None, input_flag=None, nested_fields=False):
return Binary(description=field.help_text or field.verbose_name,
required=is_required(field) and input_flag == 'create')


@convert_django_field.register(models.DecimalField)
@convert_django_field.register(models.FloatField)
@convert_django_field.register(models.DurationField)
Expand Down
Loading

0 comments on commit 428b6da

Please sign in to comment.