diff --git a/graphene-django/examples/cookbook/cookbook/ingredients/schema.py b/graphene-django/examples/cookbook/cookbook/ingredients/schema.py index 13825267..28d8555a 100644 --- a/graphene-django/examples/cookbook/cookbook/ingredients/schema.py +++ b/graphene-django/examples/cookbook/cookbook/ingredients/schema.py @@ -1,12 +1,12 @@ from cookbook.ingredients.models import Category, Ingredient from graphene import ObjectType, relay -from graphene.contrib.django.filter import DjangoFilterConnectionField -from graphene.contrib.django.types import DjangoNode +from graphene_django.filter import DjangoFilterConnectionField +from graphene_django.types import DjangoNode, DjangoObjectType # 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) -class CategoryNode(DjangoNode): +class CategoryNode(DjangoNode, DjangoObjectType): class Meta: model = Category @@ -14,7 +14,7 @@ class CategoryNode(DjangoNode): filter_order_by = ['name'] -class IngredientNode(DjangoNode): +class IngredientNode(DjangoNode, DjangoObjectType): class Meta: model = Ingredient @@ -34,6 +34,3 @@ class Query(ObjectType): ingredient = relay.NodeField(IngredientNode) all_ingredients = DjangoFilterConnectionField(IngredientNode) - - class Meta: - abstract = True diff --git a/graphene-django/examples/cookbook/cookbook/schema.py b/graphene-django/examples/cookbook/cookbook/schema.py index acb53666..ba6f02cf 100644 --- a/graphene-django/examples/cookbook/cookbook/schema.py +++ b/graphene-django/examples/cookbook/cookbook/schema.py @@ -5,5 +5,4 @@ import graphene class Query(cookbook.ingredients.schema.Query): pass -schema = graphene.Schema(name='Cookbook Schema') -schema.query = Query +schema = graphene.Schema(name='Cookbook Schema', query=Query) diff --git a/graphene-django/graphene_django/converter.py b/graphene-django/graphene_django/converter.py index bbeaa379..f5f64d39 100644 --- a/graphene-django/graphene_django/converter.py +++ b/graphene-django/graphene_django/converter.py @@ -1,7 +1,8 @@ from django.db import models 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.utils.str_converters import to_const from graphene.relay import Node, ConnectionField @@ -70,7 +71,7 @@ def convert_field_to_int(field, registry=None): @convert_django_field.register(models.BooleanField) 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) @@ -130,6 +131,8 @@ def convert_field_to_djangomodel(field, registry=None): @convert_django_field.register(ArrayField) def convert_postgres_array_to_list(field, registry=None): 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) @@ -142,4 +145,6 @@ def convert_posgres_field_to_string(field, registry=None): @convert_django_field.register(RangeField) def convert_posgres_range_to_string(field, registry=None): 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) diff --git a/graphene-django/graphene_django/tests/test_converter.py b/graphene-django/graphene_django/tests/test_converter.py index 7057f37f..28f464da 100644 --- a/graphene-django/graphene_django/tests/test_converter.py +++ b/graphene-django/graphene_django/tests/test_converter.py @@ -6,6 +6,7 @@ from py.test import raises import graphene from graphene.relay import Node, ConnectionField from graphene.types.datetime import DateTime +from graphene.types.json import JSONString from graphene.utils.get_graphql_type import get_graphql_type # 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(): - field = assert_conversion(models.BooleanField, graphene.Boolean) - assert field.required is True + field = assert_conversion(models.BooleanField, graphene.NonNull) + assert field.type.of_type == get_graphql_type(graphene.Boolean) def test_should_nullboolean_convert_boolean(): - field = assert_conversion(models.NullBooleanField, graphene.Boolean) - assert field.required is False + assert_conversion(models.NullBooleanField, graphene.Boolean) 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(): field = assert_conversion(ArrayField, graphene.List, models.CharField(max_length=100)) 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, @@ -227,7 +227,7 @@ def test_should_postgres_array_multiple_convert_list(): field = assert_conversion(ArrayField, graphene.List, ArrayField(models.CharField(max_length=100))) assert isinstance(field.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, @@ -247,4 +247,5 @@ def test_should_postgres_json_convert_string(): def test_should_postgres_range_convert_list(): from django.contrib.postgres.fields import IntegerRangeField 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) diff --git a/graphene-django/graphene_django/types.py b/graphene-django/graphene_django/types.py index 437393eb..7f08ae3a 100644 --- a/graphene-django/graphene_django/types.py +++ b/graphene-django/graphene_django/types.py @@ -39,7 +39,8 @@ class DjangoObjectTypeMeta(ObjectTypeMeta): return fields - def __new__(cls, name, bases, attrs): + @staticmethod + def _create_objecttype(cls, name, bases, attrs): # super_new = super(DjangoObjectTypeMeta, cls).__new__ super_new = type.__new__ @@ -76,6 +77,7 @@ class DjangoObjectTypeMeta(ObjectTypeMeta): fields=partial(cls._construct_fields, fields, options), interfaces=tuple(get_interfaces(interfaces + base_interfaces)) ) + options.get_fields = lambda: {} if issubclass(cls, DjangoObjectType): options.registry.register(cls) @@ -87,7 +89,7 @@ class DjangoObjectType(six.with_metaclass(DjangoObjectTypeMeta, ObjectType)): pass -class DjangoNodeMeta(NodeMeta, DjangoObjectTypeMeta): +class DjangoNodeMeta(DjangoObjectTypeMeta, NodeMeta): @staticmethod def _get_interface_options(meta): @@ -99,8 +101,9 @@ class DjangoNodeMeta(NodeMeta, DjangoObjectTypeMeta): registry=False ) - def __new__(cls, name, bases, attrs): - cls = super(DjangoNodeMeta, cls).__new__(cls, name, bases, attrs) + @staticmethod + def _create_interface(cls, name, bases, attrs): + cls = super(DjangoNodeMeta, cls)._create_interface(cls, name, bases, attrs) if not cls._meta.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) diff --git a/graphene/relay/node.py b/graphene/relay/node.py index e0d6f3d1..4089b4d5 100644 --- a/graphene/relay/node.py +++ b/graphene/relay/node.py @@ -38,7 +38,6 @@ class NodeMeta(ObjectTypeMeta): def _create_interface(cls, name, bases, attrs): options = cls._get_interface_options(attrs.pop('Meta', None)) cls = type.__new__(cls, name, bases, dict(attrs, _meta=options)) - get_node_from_global_id = getattr(cls, 'get_node_from_global_id', 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__)