mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-11 04:07:16 +03:00
Updated first passing Django tests! 🎉
This commit is contained in:
parent
b772499b9b
commit
7a29502790
|
@ -49,9 +49,9 @@ class IntroduceShip(relay.ClientIDMutation):
|
|||
faction = graphene.Field(Faction)
|
||||
|
||||
@classmethod
|
||||
def mutate_and_get_payload(cls, input, info):
|
||||
ship_name = input.get('ship_name')
|
||||
faction_id = input.get('faction_id')
|
||||
def mutate_and_get_payload(cls, input, context, info):
|
||||
ship_name = input.get('shipName')
|
||||
faction_id = input.get('factionId')
|
||||
ship = create_ship(ship_name, faction_id)
|
||||
faction = get_faction(faction_id)
|
||||
return IntroduceShip(ship=ship, faction=faction)
|
||||
|
@ -60,7 +60,7 @@ class IntroduceShip(relay.ClientIDMutation):
|
|||
class Query(graphene.ObjectType):
|
||||
rebels = graphene.Field(Faction)
|
||||
empire = graphene.Field(Faction)
|
||||
node = relay.Node.Field()
|
||||
node = DjangoNode.Field()
|
||||
ships = relay.ConnectionField(Ship, description='All the ships.')
|
||||
|
||||
@resolve_only_args
|
||||
|
@ -77,9 +77,9 @@ class Query(graphene.ObjectType):
|
|||
|
||||
|
||||
class Mutation(graphene.ObjectType):
|
||||
introduce_ship = graphene.Field(IntroduceShip)
|
||||
introduce_ship = IntroduceShip.Field()
|
||||
|
||||
|
||||
# We register the Character Model because if not would be
|
||||
# inaccessible for the schema
|
||||
schema = Schema(query=Query, mutation=Mutation, types=[])
|
||||
schema = Schema(query=Query, mutation=Mutation, types=[Ship, Character])
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
# from ...core.exceptions import SkipField
|
||||
from graphene import Field, List
|
||||
from django.db.models.query import QuerySet
|
||||
from graphene.relay import ConnectionField
|
||||
from .utils import DJANGO_FILTER_INSTALLED, get_type_for_model, maybe_queryset
|
||||
from graphql_relay.connection.arrayconnection import connection_from_list_slice
|
||||
from .utils import maybe_queryset
|
||||
|
||||
|
||||
class DjangoConnectionField(ConnectionField):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.on = kwargs.pop('on', False)
|
||||
# kwargs['default'] = kwargs.pop('default', self.get_manager)
|
||||
return super(DjangoConnectionField, self).__init__(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def model(self):
|
||||
return self.type._meta.model
|
||||
return self.connection._meta.node._meta.model
|
||||
|
||||
def get_manager(self):
|
||||
if self.on:
|
||||
|
@ -21,44 +20,22 @@ class DjangoConnectionField(ConnectionField):
|
|||
else:
|
||||
return self.model._default_manager
|
||||
|
||||
def get_queryset(self, resolved_qs, args, info):
|
||||
return resolved_qs
|
||||
def default_resolver(self, root, args, context, info):
|
||||
return getattr(root, self.source or self.attname, self.get_manager())
|
||||
|
||||
def from_list(self, connection_type, resolved, args, context, info):
|
||||
resolved_qs = maybe_queryset(resolved)
|
||||
qs = self.get_queryset(resolved_qs, args, info)
|
||||
return super(DjangoConnectionField, self).from_list(connection_type, qs, args, context, info)
|
||||
|
||||
|
||||
def get_list_or_connection_type_for_model(model):
|
||||
pass
|
||||
# field_object_type = model_field.get_object_type(schema)
|
||||
# if not field_object_type:
|
||||
# raise SkipField()
|
||||
# if isinstance(:
|
||||
# if field_object_type._meta.filter_fields:
|
||||
# field = DjangoFilterConnectionField(field_object_type)
|
||||
# else:
|
||||
# field = DjangoConnectionField(field_object_type)
|
||||
# else:
|
||||
# field = List(field_object_type)
|
||||
# field.contribute_to_class(self.object_type, self.attname)
|
||||
# return schema.T(field)
|
||||
|
||||
|
||||
def get_graphene_type_from_model(model):
|
||||
pass
|
||||
# _type = self.get_object_type(schema)
|
||||
# if not _type and self.parent._meta.only_fields:
|
||||
# raise Exception(
|
||||
# "Model %r is not accessible by the schema. "
|
||||
# "You can either register the type manually "
|
||||
# "using @schema.register. "
|
||||
# "Or disable the field in %s" % (
|
||||
# self.model,
|
||||
# self.parent,
|
||||
# )
|
||||
# )
|
||||
# if not _type:
|
||||
# raise SkipField()
|
||||
# return schema.T(_type)
|
||||
def connection_resolver(self, root, args, context, info):
|
||||
iterable = super(ConnectionField, self).resolver(root, args, context, info)
|
||||
iterable = maybe_queryset(iterable)
|
||||
if isinstance(iterable, QuerySet):
|
||||
_len = iterable.count()
|
||||
else:
|
||||
_len = len(iterable)
|
||||
return connection_from_list_slice(
|
||||
iterable,
|
||||
args,
|
||||
slice_start=0,
|
||||
list_length=_len,
|
||||
list_slice_length=_len,
|
||||
connection_type=self.connection,
|
||||
edge_type=self.connection.Edge,
|
||||
)
|
||||
|
|
|
@ -5,7 +5,7 @@ from six import StringIO
|
|||
|
||||
@patch('graphene_django.management.commands.graphql_schema.Command.save_file')
|
||||
def test_generate_file_on_call_graphql_schema(savefile_mock, settings):
|
||||
settings.GRAPHENE_SCHEMA = 'graphene_django.tests.test_urls'
|
||||
settings.GRAPHENE_SCHEMA = 'graphene_django.tests.urls'
|
||||
out = StringIO()
|
||||
management.call_command('graphql_schema', schema='', stdout=out)
|
||||
assert "Successfully dumped GraphQL schema to schema.json" in out.getvalue()
|
||||
|
|
|
@ -115,9 +115,8 @@ def test_field_with_choices_convert_enum():
|
|||
app_label = 'test'
|
||||
|
||||
graphene_type = convert_django_field_with_choices(field)
|
||||
assert issubclass(graphene_type, graphene.Enum)
|
||||
assert graphene_type._meta.graphql_type.name == 'TEST_TRANSLATEDMODEL_LANGUAGE'
|
||||
assert graphene_type._meta.graphql_type.description == 'Language'
|
||||
assert isinstance(graphene_type, graphene.Enum)
|
||||
assert graphene_type._meta.graphql_type.name == 'TranslatedModelLanguage'
|
||||
assert graphene_type._meta.enum.__members__['SPANISH'].value == 'es'
|
||||
assert graphene_type._meta.enum.__members__['ENGLISH'].value == 'en'
|
||||
|
||||
|
|
|
@ -5,11 +5,10 @@ from django.db import models
|
|||
from py.test import raises
|
||||
|
||||
import graphene
|
||||
from graphene import relay
|
||||
|
||||
from ..compat import MissingType, RangeField
|
||||
from ..types import DjangoNode, DjangoObjectType
|
||||
from ..registry import reset_global_registry
|
||||
from ..registry import reset_global_registry, get_global_registry
|
||||
from .models import Article, Reporter
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
@ -43,7 +42,7 @@ def test_should_query_well():
|
|||
reporter = graphene.Field(ReporterType)
|
||||
|
||||
def resolve_reporter(self, *args, **kwargs):
|
||||
return ReporterType(Reporter(first_name='ABA', last_name='X'))
|
||||
return Reporter(first_name='ABA', last_name='X')
|
||||
|
||||
query = '''
|
||||
query ReporterQuery {
|
||||
|
@ -119,37 +118,37 @@ def test_should_query_postgres_fields():
|
|||
|
||||
|
||||
def test_should_node():
|
||||
reset_global_registry()
|
||||
# reset_global_registry()
|
||||
# DjangoNode._meta.registry = get_global_registry()
|
||||
|
||||
class ReporterNode(DjangoNode):
|
||||
class ReporterNode(DjangoNode, DjangoObjectType):
|
||||
|
||||
class Meta:
|
||||
model = Reporter
|
||||
|
||||
@classmethod
|
||||
def get_node(cls, id, info):
|
||||
return ReporterNode(Reporter(id=2, first_name='Cookie Monster'))
|
||||
def get_node(cls, id, context, info):
|
||||
return Reporter(id=2, first_name='Cookie Monster')
|
||||
|
||||
def resolve_articles(self, *args, **kwargs):
|
||||
return [Article(headline='Hi!')]
|
||||
|
||||
class ArticleNode(DjangoNode):
|
||||
class ArticleNode(DjangoNode, DjangoObjectType):
|
||||
|
||||
class Meta:
|
||||
model = Article
|
||||
|
||||
@classmethod
|
||||
def get_node(cls, id, info):
|
||||
def get_node(cls, id, context, info):
|
||||
return Article(id=1, headline='Article node', pub_date=datetime.date(2002, 3, 11))
|
||||
|
||||
class Query(graphene.ObjectType):
|
||||
node = relay.Node.Field()
|
||||
node = DjangoNode.Field()
|
||||
reporter = graphene.Field(ReporterNode)
|
||||
article = graphene.Field(ArticleNode)
|
||||
|
||||
def resolve_reporter(self, *args, **kwargs):
|
||||
return ReporterNode(
|
||||
Reporter(id=1, first_name='ABA', last_name='X'))
|
||||
return Reporter(id=1, first_name='ABA', last_name='X')
|
||||
|
||||
query = '''
|
||||
query ReporterQuery {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from py.test import raises
|
||||
|
||||
from ..types import DjangoObjectType
|
||||
from tests.utils import assert_equal_lists
|
||||
from ..registry import Registry
|
||||
|
||||
from .models import Reporter
|
||||
|
||||
|
@ -10,7 +10,7 @@ def test_should_raise_if_no_model():
|
|||
with raises(Exception) as excinfo:
|
||||
class Character1(DjangoObjectType):
|
||||
pass
|
||||
assert 'model in the Meta' in str(excinfo.value)
|
||||
assert 'valid Django Model' in str(excinfo.value)
|
||||
|
||||
|
||||
def test_should_raise_if_model_is_invalid():
|
||||
|
@ -19,18 +19,15 @@ def test_should_raise_if_model_is_invalid():
|
|||
|
||||
class Meta:
|
||||
model = 1
|
||||
assert 'not a Django model' in str(excinfo.value)
|
||||
assert 'valid Django Model' in str(excinfo.value)
|
||||
|
||||
|
||||
def test_should_map_fields_correctly():
|
||||
class ReporterType2(DjangoObjectType):
|
||||
|
||||
class Meta:
|
||||
model = Reporter
|
||||
assert_equal_lists(
|
||||
ReporterType2._meta.fields_map.keys(),
|
||||
['articles', 'first_name', 'last_name', 'email', 'pets', 'id', 'films']
|
||||
)
|
||||
registry = Registry()
|
||||
assert list(ReporterType2._meta.graphql_type.get_fields().keys()) == ['id', 'firstName', 'lastName', 'email', 'pets', 'aChoice']
|
||||
|
||||
|
||||
def test_should_map_only_few_fields():
|
||||
|
@ -38,8 +35,6 @@ def test_should_map_only_few_fields():
|
|||
|
||||
class Meta:
|
||||
model = Reporter
|
||||
only_fields = ('id', 'email')
|
||||
assert_equal_lists(
|
||||
Reporter2._meta.fields_map.keys(),
|
||||
['id', 'email']
|
||||
)
|
||||
fields = ('id', 'email')
|
||||
|
||||
assert list(Reporter2._meta.graphql_type.get_fields().keys()) == ['id', 'email']
|
||||
|
|
|
@ -2,13 +2,13 @@ from django.conf.urls import url
|
|||
|
||||
import graphene
|
||||
from graphene import Schema
|
||||
from ..types import DjangoNode
|
||||
from ..types import DjangoNode, DjangoObjectType
|
||||
from ..views import GraphQLView
|
||||
|
||||
from .models import Article, Reporter
|
||||
|
||||
|
||||
class Character(DjangoNode):
|
||||
class Character(DjangoNode, DjangoObjectType):
|
||||
|
||||
class Meta:
|
||||
model = Reporter
|
||||
|
@ -17,7 +17,7 @@ class Character(DjangoNode):
|
|||
pass
|
||||
|
||||
|
||||
class Human(DjangoNode):
|
||||
class Human(DjangoNode, DjangoObjectType):
|
||||
raises = graphene.String()
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
import inspect
|
||||
from collections import OrderedDict
|
||||
from functools import partial
|
||||
|
||||
import six
|
||||
from django.db import models
|
||||
|
||||
from graphene import Field, Interface
|
||||
from graphene.types.objecttype import ObjectType, ObjectTypeMeta, attrs_without_fields, GrapheneObjectType, get_interfaces
|
||||
from graphene.types.interface import InterfaceTypeMeta
|
||||
from graphene.relay import Connection, Node
|
||||
from graphene.relay import Node
|
||||
from graphene.relay.node import NodeMeta
|
||||
from .converter import convert_django_field_with_choices
|
||||
from graphene.types.options import Options
|
||||
from .utils import get_model_fields
|
||||
from .utils import get_model_fields, is_valid_django_model
|
||||
from .registry import Registry, get_global_registry
|
||||
from graphene.utils.is_base_type import is_base_type
|
||||
from graphene.utils.copy_fields import copy_fields
|
||||
from graphene.utils.get_graphql_type import get_graphql_type
|
||||
from graphene.utils.get_fields import get_fields
|
||||
from graphene.utils.as_field import as_field
|
||||
|
||||
|
@ -63,8 +60,8 @@ class DjangoObjectTypeMeta(ObjectTypeMeta):
|
|||
)
|
||||
if not options.registry:
|
||||
options.registry = get_global_registry()
|
||||
assert isinstance(options.registry, Registry), 'The attribute registry in {}.Meta needs to be an instance of Registry.'.format(name)
|
||||
assert options.model, 'You need to pass a valid Django Model in {}.Meta'.format(name)
|
||||
assert isinstance(options.registry, Registry), 'The attribute registry in {}.Meta needs to be an instance of Registry, received "{}".'.format(name, options.registry)
|
||||
assert is_valid_django_model(options.model), 'You need to pass a valid Django Model in {}.Meta, received "{}".'.format(name, options.model)
|
||||
|
||||
interfaces = tuple(options.interfaces)
|
||||
fields = get_fields(ObjectType, attrs, bases, interfaces)
|
||||
|
@ -80,7 +77,7 @@ class DjangoObjectTypeMeta(ObjectTypeMeta):
|
|||
interfaces=tuple(get_interfaces(interfaces + base_interfaces))
|
||||
)
|
||||
|
||||
if issubclass(cls, DjangoObjectType):
|
||||
if issubclass(cls, DjangoObjectType):
|
||||
options.registry.register(cls)
|
||||
|
||||
return cls
|
||||
|
@ -90,8 +87,24 @@ class DjangoObjectType(six.with_metaclass(DjangoObjectTypeMeta, ObjectType)):
|
|||
pass
|
||||
|
||||
|
||||
class DjangoNodeMeta(DjangoObjectTypeMeta, NodeMeta):
|
||||
pass
|
||||
class DjangoNodeMeta(NodeMeta, DjangoObjectTypeMeta):
|
||||
|
||||
@staticmethod
|
||||
def _get_interface_options(meta):
|
||||
return Options(
|
||||
meta,
|
||||
name=None,
|
||||
description=None,
|
||||
graphql_type=None,
|
||||
registry=False
|
||||
)
|
||||
|
||||
def __new__(cls, name, bases, attrs):
|
||||
cls = super(DjangoNodeMeta, cls).__new__(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)
|
||||
return cls
|
||||
|
||||
|
||||
class DjangoNode(six.with_metaclass(DjangoNodeMeta, Node)):
|
||||
|
@ -101,3 +114,13 @@ class DjangoNode(six.with_metaclass(DjangoNodeMeta, Node)):
|
|||
return cls._meta.model.objects.get(id=id)
|
||||
except cls._meta.model.DoesNotExist:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def resolve_type(cls, type, context, info):
|
||||
# We get the model from the _meta in the Django class/instance
|
||||
model = type._meta.model
|
||||
graphene_type = cls._meta.registry.get_type_for_model(model)
|
||||
if graphene_type:
|
||||
return get_graphql_type(graphene_type)
|
||||
|
||||
raise Exception("Type not found for model \"{}\"".format(model))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import inspect
|
||||
from django.db import models
|
||||
from django.db.models.manager import Manager
|
||||
from django.db.models.query import QuerySet
|
||||
|
||||
# from graphene.utils import LazyList
|
||||
class LazyList(object):
|
||||
|
@ -54,8 +54,6 @@ class WrappedQueryset(LazyList):
|
|||
def maybe_queryset(value):
|
||||
if isinstance(value, Manager):
|
||||
value = value.get_queryset()
|
||||
if isinstance(value, QuerySet):
|
||||
return WrappedQueryset(value)
|
||||
return value
|
||||
|
||||
|
||||
|
@ -75,6 +73,10 @@ def get_related_model(field):
|
|||
return field.related_model
|
||||
|
||||
|
||||
def is_valid_django_model(model):
|
||||
return inspect.isclass(model) and issubclass(model, models.Model)
|
||||
|
||||
|
||||
def import_single_dispatch():
|
||||
try:
|
||||
from functools import singledispatch
|
||||
|
|
|
@ -2,11 +2,8 @@ from graphql_django_view import GraphQLView as BaseGraphQLView
|
|||
|
||||
|
||||
class GraphQLView(BaseGraphQLView):
|
||||
graphene_schema = None
|
||||
|
||||
def __init__(self, schema, **kwargs):
|
||||
super(GraphQLView, self).__init__(
|
||||
graphene_schema=schema,
|
||||
schema=schema,
|
||||
**kwargs
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user