Updated first passing Django tests! 🎉

This commit is contained in:
Syrus Akbary 2016-06-19 14:30:33 -07:00
parent b772499b9b
commit 7a29502790
10 changed files with 92 additions and 100 deletions

View File

@ -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])

View File

@ -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,
)

View File

@ -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()

View File

@ -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'

View File

@ -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 {

View File

@ -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']

View File

@ -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:

View File

@ -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))

View File

@ -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

View File

@ -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
)