mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-25 19:13:57 +03:00
Improved Relay types
This commit is contained in:
parent
633f72cfe9
commit
bd0ec6dc14
|
@ -31,5 +31,3 @@ from graphene.core.fields import (
|
|||
from graphene.decorators import (
|
||||
resolve_only_args
|
||||
)
|
||||
|
||||
# import graphene.relay
|
||||
|
|
|
@ -7,6 +7,7 @@ from graphene.core.fields import Field, LazyField
|
|||
from graphene.utils import cached_property, memoize, LazyMap
|
||||
|
||||
from graphene.relay.types import BaseNode
|
||||
from graphene.relay.utils import is_node
|
||||
from graphene.contrib.django.utils import get_type_for_model, lazy_map
|
||||
|
||||
|
||||
|
@ -28,7 +29,7 @@ class ConnectionOrListField(LazyField):
|
|||
def get_field(self, schema):
|
||||
model_field = self.field_type
|
||||
field_object_type = model_field.get_object_type(schema)
|
||||
if field_object_type and issubclass(field_object_type, BaseNode):
|
||||
if is_node(field_object_type):
|
||||
field = DjangoConnectionField(model_field)
|
||||
else:
|
||||
field = LazyListField(model_field)
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.db import models
|
|||
from graphene.core.options import Options
|
||||
from graphene.core.types import BaseObjectType
|
||||
from graphene.relay.utils import is_node
|
||||
from graphene.relay.types import Node
|
||||
|
||||
VALID_ATTRS = ('model', 'only_fields', 'exclude_fields')
|
||||
|
||||
|
@ -26,6 +27,7 @@ class DjangoOptions(Options):
|
|||
super(DjangoOptions, self).contribute_to_class(cls, name)
|
||||
if is_node(cls):
|
||||
self.exclude_fields += ['id']
|
||||
self.interfaces.append(Node)
|
||||
if not is_node(cls) and not is_base(cls):
|
||||
return
|
||||
if not self.model:
|
||||
|
|
|
@ -5,8 +5,8 @@ from graphene.core.types import ObjectTypeMeta, BaseObjectType
|
|||
from graphene.contrib.django.options import DjangoOptions
|
||||
from graphene.contrib.django.converter import convert_django_field
|
||||
|
||||
from graphene.relay.types import Node, BaseNode
|
||||
from graphene.relay.fields import NodeIDField
|
||||
from graphene.relay.types import BaseNode
|
||||
from graphene.relay.fields import GlobalIDField
|
||||
|
||||
|
||||
def get_reverse_fields(model):
|
||||
|
@ -53,7 +53,7 @@ class DjangoInterface(six.with_metaclass(DjangoObjectTypeMeta, BaseObjectType)):
|
|||
|
||||
|
||||
class DjangoNode(BaseNode, DjangoInterface):
|
||||
id = NodeIDField()
|
||||
id = GlobalIDField()
|
||||
|
||||
@classmethod
|
||||
def get_node(cls, id):
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
from graphene.relay.fields import (
|
||||
ConnectionField,
|
||||
NodeField
|
||||
NodeField,
|
||||
GlobalIDField,
|
||||
)
|
||||
|
||||
from graphene.relay.types import (
|
||||
Node
|
||||
)
|
||||
from graphene.relay.types import Node
|
||||
|
||||
from graphene.relay.utils import is_node
|
||||
|
|
|
@ -7,13 +7,15 @@ from graphql_relay.connection.connection import (
|
|||
connectionArgs
|
||||
)
|
||||
from graphql_relay.node.node import (
|
||||
global_id_field,
|
||||
to_global_id,
|
||||
from_global_id
|
||||
)
|
||||
from graphql.core.type import (
|
||||
GraphQLNonNull,
|
||||
GraphQLID,
|
||||
GraphQLArgument,
|
||||
)
|
||||
|
||||
from graphene.core.fields import Field, LazyNativeField, IDField
|
||||
from graphene.utils import cached_property
|
||||
from graphene.core.fields import Field, IDField
|
||||
from graphene.utils import memoize
|
||||
|
||||
|
||||
|
@ -36,44 +38,48 @@ class ConnectionField(Field):
|
|||
|
||||
@memoize
|
||||
def internal_type(self, schema):
|
||||
from graphene.relay.types import BaseNode
|
||||
from graphene.relay.utils import is_node
|
||||
object_type = self.get_object_type(schema)
|
||||
assert issubclass(
|
||||
object_type, BaseNode), 'Only nodes have connections.'
|
||||
assert is_node(object_type), 'Only nodes have connections.'
|
||||
return object_type.get_connection(schema)
|
||||
|
||||
|
||||
class NodeField(LazyNativeField):
|
||||
class NodeField(Field):
|
||||
def __init__(self, object_type=None, *args, **kwargs):
|
||||
super(NodeField, self).__init__(*args, **kwargs)
|
||||
from graphene.relay.types import Node
|
||||
super(NodeField, self).__init__(object_type or Node, *args, **kwargs)
|
||||
self.field_object_type = object_type
|
||||
self.args['id'] = GraphQLArgument(
|
||||
GraphQLNonNull(GraphQLID),
|
||||
description='The ID of an object'
|
||||
)
|
||||
|
||||
def get_object_type_field(self, schema):
|
||||
from graphene.relay.types import BaseNode
|
||||
node_field = BaseNode.get_definitions(schema).node_field
|
||||
def id_fetcher(self, global_id, info):
|
||||
from graphene.relay.utils import is_node
|
||||
schema = info.schema.graphene_schema
|
||||
resolved_global_id = from_global_id(global_id)
|
||||
_type, _id = resolved_global_id.type, resolved_global_id.id
|
||||
object_type = schema.get_type(_type)
|
||||
if not is_node(object_type) or (self.field_object_type and
|
||||
object_type != self.field_object_type):
|
||||
return
|
||||
|
||||
def resolver(instance, args, info):
|
||||
global_id = args.get('id')
|
||||
resolved_global_id = from_global_id(global_id)
|
||||
if resolved_global_id.type == self.field_object_type._meta.type_name:
|
||||
return node_field.resolver(instance, args, info)
|
||||
|
||||
args = OrderedDict(node_field.args.items())
|
||||
field = Field(self.field_object_type, id=args['id'], resolve=resolver)
|
||||
field.contribute_to_class(self.object_type, self.field_name)
|
||||
|
||||
return field.internal_field(schema)
|
||||
|
||||
def get_field(self, schema):
|
||||
if self.field_object_type:
|
||||
return self.get_object_type_field(schema)
|
||||
from graphene.relay.types import BaseNode
|
||||
return BaseNode.get_definitions(schema).node_field
|
||||
|
||||
|
||||
class NodeIDField(IDField):
|
||||
required = True
|
||||
return object_type.get_node(_id)
|
||||
|
||||
def resolve(self, instance, args, info):
|
||||
type_name = self.object_type._meta.type_name
|
||||
return to_global_id(type_name, instance.id)
|
||||
global_id = args.get('id')
|
||||
return self.id_fetcher(global_id, info)
|
||||
|
||||
|
||||
class GlobalIDField(IDField):
|
||||
'''The ID of an object'''
|
||||
required = True
|
||||
|
||||
def contribute_to_class(self, cls, name, add=True):
|
||||
from graphene.relay.utils import is_node, is_node_type
|
||||
in_node = is_node(cls) or is_node_type(cls)
|
||||
assert in_node, 'GlobalIDField could only be inside a Node, but got %r' % cls
|
||||
super(GlobalIDField, self).contribute_to_class(cls, name, add)
|
||||
|
||||
def resolve(self, instance, args, info):
|
||||
return self.object_type.to_global_id(instance, args, info)
|
||||
|
|
|
@ -1,37 +1,16 @@
|
|||
from graphql_relay.node.node import (
|
||||
node_definitions,
|
||||
from_global_id
|
||||
to_global_id
|
||||
)
|
||||
from graphql_relay.connection.connection import (
|
||||
connection_definitions
|
||||
)
|
||||
|
||||
from graphene.core.types import Interface
|
||||
from graphene.core.fields import LazyNativeField
|
||||
from graphene.relay.fields import NodeIDField
|
||||
from graphene.relay.fields import GlobalIDField
|
||||
from graphene.utils import memoize
|
||||
|
||||
|
||||
def get_node_type(schema, obj, info=None):
|
||||
return obj.internal_type(schema)
|
||||
|
||||
|
||||
def get_node(schema, global_id, *args):
|
||||
resolved_global_id = from_global_id(global_id)
|
||||
_type, _id = resolved_global_id.type, resolved_global_id.id
|
||||
object_type = schema.get_type(_type)
|
||||
if not object_type or not issubclass(object_type, BaseNode):
|
||||
raise Exception("The type %s is not a Node" % _type)
|
||||
return object_type.get_node(_id)
|
||||
|
||||
|
||||
class BaseNode(object):
|
||||
|
||||
@classmethod
|
||||
@memoize
|
||||
def get_definitions(cls, schema):
|
||||
return node_definitions(lambda *args: get_node(schema, *args), lambda *args: get_node_type(schema, *args))
|
||||
|
||||
@classmethod
|
||||
@memoize
|
||||
def get_connection(cls, schema):
|
||||
|
@ -40,14 +19,6 @@ class BaseNode(object):
|
|||
connection = connection_definitions(type_name, _type).connection_type
|
||||
return connection
|
||||
|
||||
@classmethod
|
||||
def internal_type(cls, schema):
|
||||
from graphene.relay.utils import is_node_type
|
||||
if is_node_type(cls):
|
||||
# Return only node_interface when is the Node Inerface
|
||||
return BaseNode.get_definitions(schema).node_interface
|
||||
return super(BaseNode, cls).internal_type(schema)
|
||||
|
||||
@classmethod
|
||||
def _prepare_class(cls):
|
||||
from graphene.relay.utils import is_node
|
||||
|
@ -55,6 +26,12 @@ class BaseNode(object):
|
|||
assert hasattr(
|
||||
cls, 'get_node'), 'get_node classmethod not found in %s Node' % cls
|
||||
|
||||
@classmethod
|
||||
def to_global_id(cls, instance, args, info):
|
||||
type_name = cls._meta.type_name
|
||||
return to_global_id(type_name, instance.id)
|
||||
|
||||
|
||||
class Node(BaseNode, Interface):
|
||||
id = NodeIDField()
|
||||
'''An object with an ID'''
|
||||
id = GlobalIDField()
|
||||
|
|
|
@ -2,7 +2,7 @@ from graphene.relay.types import BaseNode
|
|||
|
||||
|
||||
def is_node(object_type):
|
||||
return issubclass(object_type, BaseNode) and not is_node_type(object_type)
|
||||
return object_type and issubclass(object_type, BaseNode) and not is_node_type(object_type)
|
||||
|
||||
|
||||
def is_node_type(object_type):
|
||||
|
|
|
@ -2,7 +2,7 @@ from py.test import raises
|
|||
from collections import namedtuple
|
||||
from pytest import raises
|
||||
from graphene.relay.fields import (
|
||||
NodeIDField
|
||||
GlobalIDField
|
||||
)
|
||||
from graphene.core.fields import (
|
||||
Field,
|
||||
|
@ -62,12 +62,12 @@ def test_pseudo_interface():
|
|||
|
||||
def test_djangonode_idfield():
|
||||
idfield = DjangoNode._meta.fields_map['id']
|
||||
assert isinstance(idfield, NodeIDField)
|
||||
assert isinstance(idfield, GlobalIDField)
|
||||
|
||||
|
||||
def test_node_idfield():
|
||||
idfield = Human._meta.fields_map['id']
|
||||
assert isinstance(idfield, NodeIDField)
|
||||
assert isinstance(idfield, GlobalIDField)
|
||||
|
||||
|
||||
def test_node_replacedfield():
|
||||
|
@ -95,4 +95,9 @@ def test_object_type():
|
|||
# 'reporter': fields_map['reporter'].internal_field(schema),
|
||||
# 'pubDate': fields_map['pub_date'].internal_field(schema),
|
||||
# }
|
||||
assert object_type.get_interfaces() == [DjangoNode.internal_type(schema)]
|
||||
assert DjangoNode.internal_type(schema) in object_type.get_interfaces()
|
||||
|
||||
|
||||
def test_node_notinterface():
|
||||
assert Human._meta.interface is False
|
||||
assert DjangoNode in Human._meta.interfaces
|
||||
|
|
Loading…
Reference in New Issue
Block a user