mirror of
				https://github.com/graphql-python/graphene.git
				synced 2025-11-04 18:07:48 +03:00 
			
		
		
		
	Improved Django model conversion
This commit is contained in:
		
							parent
							
								
									2e8707aee6
								
							
						
					
					
						commit
						76147d7c26
					
				| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										23
									
								
								graphene/contrib/django/fields.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								graphene/contrib/django/fields.py
									
									
									
									
									
										Normal 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)
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user