Improved Django model conversion

This commit is contained in:
Syrus Akbary 2015-09-28 01:51:51 -07:00
parent 2e8707aee6
commit 76147d7c26
7 changed files with 77 additions and 11 deletions

View File

@ -7,34 +7,48 @@ from graphene.core.fields import (
IntField,
BooleanField,
FloatField,
ListField
)
from graphene.contrib.django.fields import DjangoModelField
@singledispatch
def convert_django_field(field):
raise Exception("Don't know how to convert the Django field %s"%field)
def convert_django_field(field, cls):
raise Exception("Don't know how to convert the Django field %s (%s)" % (field, field.__class__))
@convert_django_field.register(models.DateField)
@convert_django_field.register(models.CharField)
def _(field):
@convert_django_field.register(models.TextField)
def _(field, cls):
return StringField(description=field.help_text)
@convert_django_field.register(models.AutoField)
def _(field):
def _(field, cls):
return IDField(description=field.help_text)
@convert_django_field.register(models.BigIntegerField)
@convert_django_field.register(models.IntegerField)
def _(field):
def _(field, cls):
return IntField(description=field.help_text)
@convert_django_field.register(models.BooleanField)
def _(field):
def _(field, cls):
return BooleanField(description=field.help_text)
@convert_django_field.register(models.FloatField)
def _(field):
def _(field, cls):
return FloatField(description=field.help_text)
@convert_django_field.register(models.ManyToOneRel)
def _(field, cls):
return ListField(DjangoModelField(field.related_model))
@convert_django_field.register(models.ForeignKey)
def _(field, cls):
return DjangoModelField(field.related_model)

View File

@ -0,0 +1,23 @@
from graphene.core.fields import Field
from graphene.utils import cached_property
from graphene.env import get_global_schema
def get_type_for_model(schema, model):
schema = schema or get_global_schema()
types = schema.types.values()
for _type in types:
type_model = getattr(_type._meta, 'model', None)
if model == type_model:
return _type._meta.type
class DjangoModelField(Field):
def __init__(self, model):
super(DjangoModelField, self).__init__(None)
self.model = model
@cached_property
def type(self):
return get_type_for_model(self.schema, self.model)

View File

@ -1,4 +1,5 @@
import six
from django.db import models
from graphene.core.types import ObjectTypeMeta, ObjectType
from graphene.contrib.django.options import DjangoOptions
@ -6,6 +7,13 @@ from graphene.contrib.django.converter import convert_django_field
from graphene.relay import Node
def get_reverse_fields(model):
for name, attr in model.__dict__.items():
related = getattr(attr, 'related', None)
if isinstance(related, models.ManyToOneRel):
yield related
class DjangoObjectTypeMeta(ObjectTypeMeta):
options_cls = DjangoOptions
def add_extra_fields(cls):
@ -14,10 +22,11 @@ class DjangoObjectTypeMeta(ObjectTypeMeta):
only_fields = cls._meta.only_fields
# print cls._meta.model._meta._get_fields(forward=False, reverse=True, include_hidden=True)
for field in cls._meta.model._meta.fields:
reverse_fields = tuple(get_reverse_fields(cls._meta.model))
for field in cls._meta.model._meta.fields + reverse_fields:
if only_fields and field.name not in only_fields:
continue
converted_field = convert_django_field(field)
converted_field = convert_django_field(field, cls)
cls.add_to_class(field.name, converted_field)

View File

@ -76,8 +76,8 @@ class Field(object):
@cached_property
def field(self):
if not self.field_type:
raise Exception('Must specify a field GraphQL type for the field %s'%self.field_name)
# if not self.field_type:
# raise Exception('Must specify a field GraphQL type for the field %s'%self.field_name)
if not self.object_type:
raise Exception('Field could not be constructed in a non graphene.Type or graphene.Interface')

View File

@ -16,6 +16,14 @@ class Options(object):
self.parents = []
self.valid_attrs = DEFAULT_NAMES
# @property
# def schema(self):
# return self._schema or get_global_schema()
# @schema.setter
# def schema(self, schema):
# self._schema = schema
def contribute_to_class(self, cls, name):
cls._meta = self
self.parent = cls

View File

@ -42,6 +42,10 @@ class Schema(object):
raise Exception('Type %s not found in %r' % (type_name, self))
return self._types[type_name]
@property
def types(self):
return self._types
def execute(self, request='', root=None, vars=None, operation_name=None):
root = root or object()
return graphql(

View File

@ -74,6 +74,14 @@ def test_should_node():
def get_node(cls, id):
return ReporterNodeType(Reporter(id=2, first_name='Cookie Monster'))
class ArticleNodeType(DjangoNode):
class Meta:
model = Article
@classmethod
def get_node(cls, id):
return ArticleNodeType(None)
class Query(graphene.ObjectType):
node = relay.NodeField()
reporter = graphene.Field(ReporterNodeType)