mirror of
https://github.com/graphql-python/graphene.git
synced 2025-02-02 12:44:15 +03:00
Improved fields ordering. Thanks @leebyron for pointing this!
Not everything yet fixed. Have to fix too in graphql-core/relay
This commit is contained in:
parent
fbd9465e57
commit
0bc0218032
|
@ -25,10 +25,10 @@ class DjangoObjectTypeMeta(ObjectTypeMeta):
|
||||||
if not cls._meta.model:
|
if not cls._meta.model:
|
||||||
return
|
return
|
||||||
only_fields = cls._meta.only_fields
|
only_fields = cls._meta.only_fields
|
||||||
reverse_fields = tuple(get_reverse_fields(cls._meta.model))
|
reverse_fields = get_reverse_fields(cls._meta.model)
|
||||||
all_fields = (list(cls._meta.model._meta.fields) +
|
all_fields = sorted(list(cls._meta.model._meta.fields) +
|
||||||
list(reverse_fields) +
|
list(reverse_fields) +
|
||||||
list(cls._meta.model._meta.local_many_to_many))
|
list(cls._meta.model._meta.local_many_to_many))
|
||||||
|
|
||||||
for field in all_fields:
|
for field in all_fields:
|
||||||
is_not_in_only = only_fields and field.name not in only_fields
|
is_not_in_only = only_fields and field.name not in only_fields
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import inspect
|
import inspect
|
||||||
import six
|
import six
|
||||||
|
from functools import total_ordering
|
||||||
from graphql.core.type import (
|
from graphql.core.type import (
|
||||||
GraphQLField,
|
GraphQLField,
|
||||||
GraphQLList,
|
GraphQLList,
|
||||||
|
@ -16,8 +17,10 @@ from graphene.core.types import BaseObjectType
|
||||||
from graphene.core.scalars import GraphQLSkipField
|
from graphene.core.scalars import GraphQLSkipField
|
||||||
|
|
||||||
|
|
||||||
|
@total_ordering
|
||||||
class Field(object):
|
class Field(object):
|
||||||
SKIP = GraphQLSkipField
|
SKIP = GraphQLSkipField
|
||||||
|
creation_counter = 0
|
||||||
|
|
||||||
def __init__(self, field_type, name=None, resolve=None, required=False, args=None, description='', **extra_args):
|
def __init__(self, field_type, name=None, resolve=None, required=False, args=None, description='', **extra_args):
|
||||||
self.field_type = field_type
|
self.field_type = field_type
|
||||||
|
@ -29,6 +32,8 @@ class Field(object):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.description = description or self.__doc__
|
self.description = description or self.__doc__
|
||||||
self.object_type = None
|
self.object_type = None
|
||||||
|
self.creation_counter = Field.creation_counter
|
||||||
|
Field.creation_counter += 1
|
||||||
|
|
||||||
def contribute_to_class(self, cls, name):
|
def contribute_to_class(self, cls, name):
|
||||||
if not self.name:
|
if not self.name:
|
||||||
|
@ -122,6 +127,21 @@ class Field(object):
|
||||||
return '<%s: %s>' % (path, name)
|
return '<%s: %s>' % (path, name)
|
||||||
return '<%s>' % path
|
return '<%s>' % path
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
# Needed for @total_ordering
|
||||||
|
if isinstance(other, Field):
|
||||||
|
return self.creation_counter == other.creation_counter
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
# This is needed because bisect does not take a comparison function.
|
||||||
|
if isinstance(other, Field):
|
||||||
|
return self.creation_counter < other.creation_counter
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self.creation_counter)
|
||||||
|
|
||||||
|
|
||||||
class NativeField(Field):
|
class NativeField(Field):
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from graphene.utils import cached_property
|
from graphene.utils import cached_property
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
DEFAULT_NAMES = ('description', 'name', 'interface',
|
DEFAULT_NAMES = ('description', 'name', 'interface',
|
||||||
'type_name', 'interfaces', 'proxy')
|
'type_name', 'interfaces', 'proxy')
|
||||||
|
@ -66,12 +67,8 @@ class Options(object):
|
||||||
fields = []
|
fields = []
|
||||||
for parent in self.parents:
|
for parent in self.parents:
|
||||||
fields.extend(parent._meta.fields)
|
fields.extend(parent._meta.fields)
|
||||||
return self.local_fields + fields
|
return sorted(self.local_fields + fields)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def fields_map(self):
|
def fields_map(self):
|
||||||
return {f.field_name: f for f in self.fields}
|
return OrderedDict([(f.field_name, f) for f in self.fields])
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def internal_fields_map(self):
|
|
||||||
return {f.name: f for f in self.fields}
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import inspect
|
import inspect
|
||||||
import six
|
import six
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
from graphql.core.type import (
|
from graphql.core.type import (
|
||||||
GraphQLObjectType,
|
GraphQLObjectType,
|
||||||
|
@ -49,10 +50,9 @@ class ObjectTypeMeta(type):
|
||||||
new_class.add_extra_fields()
|
new_class.add_extra_fields()
|
||||||
|
|
||||||
new_fields = new_class._meta.local_fields
|
new_fields = new_class._meta.local_fields
|
||||||
field_names = {f.name:f for f in new_fields}
|
field_names = {f.name: f for f in new_fields}
|
||||||
|
|
||||||
for base in parents:
|
for base in parents:
|
||||||
original_base = base
|
|
||||||
if not hasattr(base, '_meta'):
|
if not hasattr(base, '_meta'):
|
||||||
# Things without _meta aren't functional models, so they're
|
# Things without _meta aren't functional models, so they're
|
||||||
# uninteresting parents.
|
# uninteresting parents.
|
||||||
|
@ -132,11 +132,9 @@ class BaseObjectType(object):
|
||||||
@memoize
|
@memoize
|
||||||
@register_internal_type
|
@register_internal_type
|
||||||
def internal_type(cls, schema):
|
def internal_type(cls, schema):
|
||||||
fields_map = cls._meta.internal_fields_map
|
fields_list = cls._meta.fields
|
||||||
fields = lambda: {
|
fields = lambda: OrderedDict([(f.name, f.internal_field(schema))
|
||||||
name: field.internal_field(schema)
|
for f in fields_list])
|
||||||
for name, field in fields_map.items()
|
|
||||||
}
|
|
||||||
if cls._meta.interface:
|
if cls._meta.interface:
|
||||||
return GraphQLInterfaceType(
|
return GraphQLInterfaceType(
|
||||||
cls._meta.type_name,
|
cls._meta.type_name,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import collections
|
from collections import Iterable, OrderedDict
|
||||||
|
|
||||||
from graphql_relay.connection.arrayconnection import (
|
from graphql_relay.connection.arrayconnection import (
|
||||||
connectionFromArray
|
connectionFromArray
|
||||||
|
@ -30,7 +30,7 @@ class ConnectionField(Field):
|
||||||
if resolved:
|
if resolved:
|
||||||
resolved = self.wrap_resolved(resolved, instance, args, info)
|
resolved = self.wrap_resolved(resolved, instance, args, info)
|
||||||
assert isinstance(
|
assert isinstance(
|
||||||
resolved, collections.Iterable), 'Resolved value from the connection field have to be iterable'
|
resolved, Iterable), 'Resolved value from the connection field have to be iterable'
|
||||||
return connectionFromArray(resolved, args)
|
return connectionFromArray(resolved, args)
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
|
@ -71,7 +71,7 @@ class NodeTypeField(LazyField):
|
||||||
if resolved_global_id.type == self.field_object_type._meta.type_name:
|
if resolved_global_id.type == self.field_object_type._meta.type_name:
|
||||||
return node_field.resolver(instance, args, info)
|
return node_field.resolver(instance, args, info)
|
||||||
|
|
||||||
args = {a.name: a for a in node_field.args}
|
args = OrderedDict([(a.name, a) for a in node_field.args])
|
||||||
field = Field(self.field_object_type, id=args['id'], resolve=resolver)
|
field = Field(self.field_object_type, id=args['id'], resolve=resolver)
|
||||||
field.contribute_to_class(self.object_type, self.field_name)
|
field.contribute_to_class(self.object_type, self.field_name)
|
||||||
|
|
||||||
|
|
|
@ -63,13 +63,13 @@ def test_interface_resolve_type():
|
||||||
|
|
||||||
def test_object_type():
|
def test_object_type():
|
||||||
object_type = Human.internal_type(schema)
|
object_type = Human.internal_type(schema)
|
||||||
internal_fields_map = Human._meta.internal_fields_map
|
fields_map = Human._meta.fields_map
|
||||||
assert Human._meta.interface is False
|
assert Human._meta.interface is False
|
||||||
assert isinstance(object_type, GraphQLObjectType)
|
assert isinstance(object_type, GraphQLObjectType)
|
||||||
assert object_type.get_fields() == {
|
assert object_type.get_fields() == {
|
||||||
'headline': internal_fields_map['headline'].internal_field(schema),
|
'headline': fields_map['headline'].internal_field(schema),
|
||||||
'id': internal_fields_map['id'].internal_field(schema),
|
'id': fields_map['id'].internal_field(schema),
|
||||||
'reporter': internal_fields_map['reporter'].internal_field(schema),
|
'reporter': fields_map['reporter'].internal_field(schema),
|
||||||
'pubDate': internal_fields_map['pubDate'].internal_field(schema),
|
'pubDate': fields_map['pub_date'].internal_field(schema),
|
||||||
}
|
}
|
||||||
assert object_type.get_interfaces() == [DjangoNode.internal_type(schema)]
|
assert object_type.get_interfaces() == [DjangoNode.internal_type(schema)]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user