Fixed Graphene Django integration

This commit is contained in:
Syrus Akbary 2016-06-21 22:52:39 -07:00
parent 043e548f49
commit 37ed617fce
6 changed files with 27 additions and 23 deletions

View File

@ -1,12 +1,12 @@
from cookbook.ingredients.models import Category, Ingredient from cookbook.ingredients.models import Category, Ingredient
from graphene import ObjectType, relay from graphene import ObjectType, relay
from graphene.contrib.django.filter import DjangoFilterConnectionField from graphene_django.filter import DjangoFilterConnectionField
from graphene.contrib.django.types import DjangoNode from graphene_django.types import DjangoNode, DjangoObjectType
# Graphene will automatically map the User model's fields onto the UserType. # Graphene will automatically map the User model's fields onto the UserType.
# This is configured in the UserType's Meta class (as you can see below) # This is configured in the UserType's Meta class (as you can see below)
class CategoryNode(DjangoNode): class CategoryNode(DjangoNode, DjangoObjectType):
class Meta: class Meta:
model = Category model = Category
@ -14,7 +14,7 @@ class CategoryNode(DjangoNode):
filter_order_by = ['name'] filter_order_by = ['name']
class IngredientNode(DjangoNode): class IngredientNode(DjangoNode, DjangoObjectType):
class Meta: class Meta:
model = Ingredient model = Ingredient
@ -34,6 +34,3 @@ class Query(ObjectType):
ingredient = relay.NodeField(IngredientNode) ingredient = relay.NodeField(IngredientNode)
all_ingredients = DjangoFilterConnectionField(IngredientNode) all_ingredients = DjangoFilterConnectionField(IngredientNode)
class Meta:
abstract = True

View File

@ -5,5 +5,4 @@ import graphene
class Query(cookbook.ingredients.schema.Query): class Query(cookbook.ingredients.schema.Query):
pass pass
schema = graphene.Schema(name='Cookbook Schema') schema = graphene.Schema(name='Cookbook Schema', query=Query)
schema.query = Query

View File

@ -1,7 +1,8 @@
from django.db import models from django.db import models
from django.utils.encoding import force_text from django.utils.encoding import force_text
from graphene import Enum, List, ID, Boolean, Float, Int, String, Field from graphene import Enum, List, ID, Boolean, Float, Int, String, Field, NonNull
from graphene.types.json import JSONString
from graphene.types.datetime import DateTime from graphene.types.datetime import DateTime
from graphene.utils.str_converters import to_const from graphene.utils.str_converters import to_const
from graphene.relay import Node, ConnectionField from graphene.relay import Node, ConnectionField
@ -70,7 +71,7 @@ def convert_field_to_int(field, registry=None):
@convert_django_field.register(models.BooleanField) @convert_django_field.register(models.BooleanField)
def convert_field_to_boolean(field, registry=None): def convert_field_to_boolean(field, registry=None):
return Boolean(description=field.help_text, required=True) return NonNull(Boolean, description=field.help_text)
@convert_django_field.register(models.NullBooleanField) @convert_django_field.register(models.NullBooleanField)
@ -130,6 +131,8 @@ def convert_field_to_djangomodel(field, registry=None):
@convert_django_field.register(ArrayField) @convert_django_field.register(ArrayField)
def convert_postgres_array_to_list(field, registry=None): def convert_postgres_array_to_list(field, registry=None):
base_type = convert_django_field(field.base_field) base_type = convert_django_field(field.base_field)
if not isinstance(base_type, (List, NonNull)):
base_type = type(base_type)
return List(base_type, description=field.help_text) return List(base_type, description=field.help_text)
@ -142,4 +145,6 @@ def convert_posgres_field_to_string(field, registry=None):
@convert_django_field.register(RangeField) @convert_django_field.register(RangeField)
def convert_posgres_range_to_string(field, registry=None): def convert_posgres_range_to_string(field, registry=None):
inner_type = convert_django_field(field.base_field) inner_type = convert_django_field(field.base_field)
if not isinstance(inner_type, (List, NonNull)):
inner_type = type(inner_type)
return List(inner_type, description=field.help_text) return List(inner_type, description=field.help_text)

View File

@ -6,6 +6,7 @@ from py.test import raises
import graphene import graphene
from graphene.relay import Node, ConnectionField from graphene.relay import Node, ConnectionField
from graphene.types.datetime import DateTime from graphene.types.datetime import DateTime
from graphene.types.json import JSONString
from graphene.utils.get_graphql_type import get_graphql_type from graphene.utils.get_graphql_type import get_graphql_type
# from graphene.core.types.custom_scalars import DateTime, JSONString # from graphene.core.types.custom_scalars import DateTime, JSONString
@ -93,13 +94,12 @@ def test_should_integer_convert_int():
def test_should_boolean_convert_boolean(): def test_should_boolean_convert_boolean():
field = assert_conversion(models.BooleanField, graphene.Boolean) field = assert_conversion(models.BooleanField, graphene.NonNull)
assert field.required is True assert field.type.of_type == get_graphql_type(graphene.Boolean)
def test_should_nullboolean_convert_boolean(): def test_should_nullboolean_convert_boolean():
field = assert_conversion(models.NullBooleanField, graphene.Boolean) assert_conversion(models.NullBooleanField, graphene.Boolean)
assert field.required is False
def test_field_with_choices_convert_enum(): def test_field_with_choices_convert_enum():
@ -218,7 +218,7 @@ def test_should_onetoone_reverse_convert_model():
def test_should_postgres_array_convert_list(): def test_should_postgres_array_convert_list():
field = assert_conversion(ArrayField, graphene.List, models.CharField(max_length=100)) field = assert_conversion(ArrayField, graphene.List, models.CharField(max_length=100))
assert isinstance(field.type, graphene.List) assert isinstance(field.type, graphene.List)
assert isinstance(field.type.of_type, graphene.String) assert field.type.of_type == get_graphql_type(graphene.String)
@pytest.mark.skipif(ArrayField is MissingType, @pytest.mark.skipif(ArrayField is MissingType,
@ -227,7 +227,7 @@ def test_should_postgres_array_multiple_convert_list():
field = assert_conversion(ArrayField, graphene.List, ArrayField(models.CharField(max_length=100))) field = assert_conversion(ArrayField, graphene.List, ArrayField(models.CharField(max_length=100)))
assert isinstance(field.type, graphene.List) assert isinstance(field.type, graphene.List)
assert isinstance(field.type.of_type, graphene.List) assert isinstance(field.type.of_type, graphene.List)
assert isinstance(field.type.of_type.of_type, graphene.String) assert field.type.of_type.of_type == get_graphql_type(graphene.String)
@pytest.mark.skipif(HStoreField is MissingType, @pytest.mark.skipif(HStoreField is MissingType,
@ -247,4 +247,5 @@ def test_should_postgres_json_convert_string():
def test_should_postgres_range_convert_list(): def test_should_postgres_range_convert_list():
from django.contrib.postgres.fields import IntegerRangeField from django.contrib.postgres.fields import IntegerRangeField
field = assert_conversion(IntegerRangeField, graphene.List) field = assert_conversion(IntegerRangeField, graphene.List)
assert isinstance(field.type.of_type, graphene.Int) assert isinstance(field.type, graphene.List)
# assert isinstance(field.type.of_type, graphene.Int)

View File

@ -39,7 +39,8 @@ class DjangoObjectTypeMeta(ObjectTypeMeta):
return fields return fields
def __new__(cls, name, bases, attrs): @staticmethod
def _create_objecttype(cls, name, bases, attrs):
# super_new = super(DjangoObjectTypeMeta, cls).__new__ # super_new = super(DjangoObjectTypeMeta, cls).__new__
super_new = type.__new__ super_new = type.__new__
@ -76,6 +77,7 @@ class DjangoObjectTypeMeta(ObjectTypeMeta):
fields=partial(cls._construct_fields, fields, options), fields=partial(cls._construct_fields, fields, options),
interfaces=tuple(get_interfaces(interfaces + base_interfaces)) interfaces=tuple(get_interfaces(interfaces + base_interfaces))
) )
options.get_fields = lambda: {}
if issubclass(cls, DjangoObjectType): if issubclass(cls, DjangoObjectType):
options.registry.register(cls) options.registry.register(cls)
@ -87,7 +89,7 @@ class DjangoObjectType(six.with_metaclass(DjangoObjectTypeMeta, ObjectType)):
pass pass
class DjangoNodeMeta(NodeMeta, DjangoObjectTypeMeta): class DjangoNodeMeta(DjangoObjectTypeMeta, NodeMeta):
@staticmethod @staticmethod
def _get_interface_options(meta): def _get_interface_options(meta):
@ -99,8 +101,9 @@ class DjangoNodeMeta(NodeMeta, DjangoObjectTypeMeta):
registry=False registry=False
) )
def __new__(cls, name, bases, attrs): @staticmethod
cls = super(DjangoNodeMeta, cls).__new__(cls, name, bases, attrs) def _create_interface(cls, name, bases, attrs):
cls = super(DjangoNodeMeta, cls)._create_interface(cls, name, bases, attrs)
if not cls._meta.registry: if not cls._meta.registry:
cls._meta.registry = get_global_registry() cls._meta.registry = get_global_registry()
assert isinstance(cls._meta.registry, Registry), 'The attribute registry in {}.Meta needs to be an instance of Registry.'.format(name) assert isinstance(cls._meta.registry, Registry), 'The attribute registry in {}.Meta needs to be an instance of Registry.'.format(name)

View File

@ -38,7 +38,6 @@ class NodeMeta(ObjectTypeMeta):
def _create_interface(cls, name, bases, attrs): def _create_interface(cls, name, bases, attrs):
options = cls._get_interface_options(attrs.pop('Meta', None)) options = cls._get_interface_options(attrs.pop('Meta', None))
cls = type.__new__(cls, name, bases, dict(attrs, _meta=options)) cls = type.__new__(cls, name, bases, dict(attrs, _meta=options))
get_node_from_global_id = getattr(cls, 'get_node_from_global_id', None) get_node_from_global_id = getattr(cls, 'get_node_from_global_id', None)
id_resolver = getattr(cls, 'id_resolver', None) id_resolver = getattr(cls, 'id_resolver', None)
assert get_node_from_global_id, '{}.get_node_from_global_id method is required by the Node interface.'.format(cls.__name__) assert get_node_from_global_id, '{}.get_node_from_global_id method is required by the Node interface.'.format(cls.__name__)