mirror of
				https://github.com/graphql-python/graphene.git
				synced 2025-11-04 01:47:45 +03:00 
			
		
		
		
	Improved django support
This commit is contained in:
		
							parent
							
								
									b0f2b4dd55
								
							
						
					
					
						commit
						cf657b365c
					
				| 
						 | 
				
			
			@ -5,6 +5,7 @@ from graphene.contrib.django.fields import (ConnectionOrListField,
 | 
			
		|||
                                            DjangoModelField)
 | 
			
		||||
from graphene.core.fields import (BooleanField, FloatField, IDField, IntField,
 | 
			
		||||
                                  StringField)
 | 
			
		||||
from graphene.core.types.scalars import Boolean, Float, ID, Int, String
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    UUIDField = models.UUIDField
 | 
			
		||||
| 
						 | 
				
			
			@ -28,12 +29,12 @@ def convert_django_field(field):
 | 
			
		|||
@convert_django_field.register(models.URLField)
 | 
			
		||||
@convert_django_field.register(UUIDField)
 | 
			
		||||
def convert_field_to_string(field):
 | 
			
		||||
    return StringField(description=field.help_text)
 | 
			
		||||
    return String(description=field.help_text)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@convert_django_field.register(models.AutoField)
 | 
			
		||||
def convert_field_to_id(field):
 | 
			
		||||
    return IDField(description=field.help_text)
 | 
			
		||||
    return ID(description=field.help_text)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@convert_django_field.register(models.PositiveIntegerField)
 | 
			
		||||
| 
						 | 
				
			
			@ -42,23 +43,23 @@ def convert_field_to_id(field):
 | 
			
		|||
@convert_django_field.register(models.BigIntegerField)
 | 
			
		||||
@convert_django_field.register(models.IntegerField)
 | 
			
		||||
def convert_field_to_int(field):
 | 
			
		||||
    return IntField(description=field.help_text)
 | 
			
		||||
    return Int(description=field.help_text)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@convert_django_field.register(models.BooleanField)
 | 
			
		||||
def convert_field_to_boolean(field):
 | 
			
		||||
    return BooleanField(description=field.help_text, required=True)
 | 
			
		||||
    return Boolean(description=field.help_text, required=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@convert_django_field.register(models.NullBooleanField)
 | 
			
		||||
def convert_field_to_nullboolean(field):
 | 
			
		||||
    return BooleanField(description=field.help_text)
 | 
			
		||||
    return Boolean(description=field.help_text)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@convert_django_field.register(models.DecimalField)
 | 
			
		||||
@convert_django_field.register(models.FloatField)
 | 
			
		||||
def convert_field_to_float(field):
 | 
			
		||||
    return FloatField(description=field.help_text)
 | 
			
		||||
    return Float(description=field.help_text)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@convert_django_field.register(models.ManyToManyField)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
from graphene import relay
 | 
			
		||||
from graphene.contrib.django.utils import get_type_for_model, lazy_map
 | 
			
		||||
from graphene.core.fields import Field, LazyField, ListField
 | 
			
		||||
from graphene.core.fields import Field, ListField
 | 
			
		||||
from graphene.core.types.base import FieldType
 | 
			
		||||
from graphene.relay.utils import is_node
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8,60 +9,49 @@ class DjangoConnectionField(relay.ConnectionField):
 | 
			
		|||
 | 
			
		||||
    def wrap_resolved(self, value, instance, args, info):
 | 
			
		||||
        schema = info.schema.graphene_schema
 | 
			
		||||
        return lazy_map(value, self.get_object_type(schema))
 | 
			
		||||
        return lazy_map(value, self.type.get_object_type(schema))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LazyListField(ListField):
 | 
			
		||||
 | 
			
		||||
    def resolve(self, instance, args, info):
 | 
			
		||||
    def resolver(self, instance, args, info):
 | 
			
		||||
        schema = info.schema.graphene_schema
 | 
			
		||||
        resolved = super(LazyListField, self).resolve(instance, args, info)
 | 
			
		||||
        resolved = super(LazyListField, self).resolver(instance, args, info)
 | 
			
		||||
        return lazy_map(resolved, self.get_object_type(schema))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConnectionOrListField(LazyField):
 | 
			
		||||
class ConnectionOrListField(Field):
 | 
			
		||||
 | 
			
		||||
    def get_field(self, schema):
 | 
			
		||||
        model_field = self.field_type
 | 
			
		||||
    def internal_type(self, schema):
 | 
			
		||||
        model_field = self.type
 | 
			
		||||
        field_object_type = model_field.get_object_type(schema)
 | 
			
		||||
        if is_node(field_object_type):
 | 
			
		||||
            field = DjangoConnectionField(model_field)
 | 
			
		||||
        else:
 | 
			
		||||
            field = LazyListField(model_field)
 | 
			
		||||
        field.contribute_to_class(self.object_type, self.name)
 | 
			
		||||
        return field
 | 
			
		||||
        return field.internal_type(schema)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DjangoModelField(Field):
 | 
			
		||||
class DjangoModelField(FieldType):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, model, *args, **kwargs):
 | 
			
		||||
        super(DjangoModelField, self).__init__(None, *args, **kwargs)
 | 
			
		||||
        self.model = model
 | 
			
		||||
 | 
			
		||||
    def resolve(self, instance, args, info):
 | 
			
		||||
        resolved = super(DjangoModelField, self).resolve(instance, args, info)
 | 
			
		||||
        schema = info.schema.graphene_schema
 | 
			
		||||
        _type = self.get_object_type(schema)
 | 
			
		||||
        assert _type, ("Field %s cannot be retrieved as the "
 | 
			
		||||
                       "ObjectType is not registered by the schema" % (
 | 
			
		||||
                           self.attname
 | 
			
		||||
                       ))
 | 
			
		||||
        return _type(resolved)
 | 
			
		||||
        super(DjangoModelField, self).__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def internal_type(self, schema):
 | 
			
		||||
        _type = self.get_object_type(schema)
 | 
			
		||||
        if not _type and self.object_type._meta.only_fields:
 | 
			
		||||
        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 %s in %s" % (
 | 
			
		||||
                "Or disable the field in %s" % (
 | 
			
		||||
                    self.model,
 | 
			
		||||
                    self.attname,
 | 
			
		||||
                    self.object_type
 | 
			
		||||
                    self.parent,
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        return schema.T(_type) or Field.SKIP
 | 
			
		||||
        return schema.T(_type)
 | 
			
		||||
 | 
			
		||||
    def get_object_type(self, schema):
 | 
			
		||||
        return get_type_for_model(schema, self.model)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,8 +15,9 @@ def assert_conversion(django_field, graphene_field, *args):
 | 
			
		|||
    field = django_field(*args, help_text='Custom Help Text')
 | 
			
		||||
    graphene_type = convert_django_field(field)
 | 
			
		||||
    assert isinstance(graphene_type, graphene_field)
 | 
			
		||||
    assert graphene_type.description == 'Custom Help Text'
 | 
			
		||||
    return graphene_type
 | 
			
		||||
    field = graphene_type.as_field()
 | 
			
		||||
    assert field.description == 'Custom Help Text'
 | 
			
		||||
    return field
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_unknown_django_field_raise_exception():
 | 
			
		||||
| 
						 | 
				
			
			@ -26,86 +27,86 @@ def test_should_unknown_django_field_raise_exception():
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def test_should_date_convert_string():
 | 
			
		||||
    assert_conversion(models.DateField, graphene.StringField)
 | 
			
		||||
    assert_conversion(models.DateField, graphene.String)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_char_convert_string():
 | 
			
		||||
    assert_conversion(models.CharField, graphene.StringField)
 | 
			
		||||
    assert_conversion(models.CharField, graphene.String)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_text_convert_string():
 | 
			
		||||
    assert_conversion(models.TextField, graphene.StringField)
 | 
			
		||||
    assert_conversion(models.TextField, graphene.String)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_email_convert_string():
 | 
			
		||||
    assert_conversion(models.EmailField, graphene.StringField)
 | 
			
		||||
    assert_conversion(models.EmailField, graphene.String)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_slug_convert_string():
 | 
			
		||||
    assert_conversion(models.SlugField, graphene.StringField)
 | 
			
		||||
    assert_conversion(models.SlugField, graphene.String)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_url_convert_string():
 | 
			
		||||
    assert_conversion(models.URLField, graphene.StringField)
 | 
			
		||||
    assert_conversion(models.URLField, graphene.String)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_auto_convert_id():
 | 
			
		||||
    assert_conversion(models.AutoField, graphene.IDField)
 | 
			
		||||
    assert_conversion(models.AutoField, graphene.ID)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_positive_integer_convert_int():
 | 
			
		||||
    assert_conversion(models.PositiveIntegerField, graphene.IntField)
 | 
			
		||||
    assert_conversion(models.PositiveIntegerField, graphene.Int)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_positive_small_convert_int():
 | 
			
		||||
    assert_conversion(models.PositiveSmallIntegerField, graphene.IntField)
 | 
			
		||||
    assert_conversion(models.PositiveSmallIntegerField, graphene.Int)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_small_integer_convert_int():
 | 
			
		||||
    assert_conversion(models.SmallIntegerField, graphene.IntField)
 | 
			
		||||
    assert_conversion(models.SmallIntegerField, graphene.Int)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_big_integer_convert_int():
 | 
			
		||||
    assert_conversion(models.BigIntegerField, graphene.IntField)
 | 
			
		||||
    assert_conversion(models.BigIntegerField, graphene.Int)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_integer_convert_int():
 | 
			
		||||
    assert_conversion(models.IntegerField, graphene.IntField)
 | 
			
		||||
    assert_conversion(models.IntegerField, graphene.Int)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_boolean_convert_boolean():
 | 
			
		||||
    field = assert_conversion(models.BooleanField, graphene.BooleanField)
 | 
			
		||||
    field = assert_conversion(models.BooleanField, graphene.Boolean)
 | 
			
		||||
    assert field.required is True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_nullboolean_convert_boolean():
 | 
			
		||||
    field = assert_conversion(models.NullBooleanField, graphene.BooleanField)
 | 
			
		||||
    field = assert_conversion(models.NullBooleanField, graphene.Boolean)
 | 
			
		||||
    assert field.required is False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_float_convert_float():
 | 
			
		||||
    assert_conversion(models.FloatField, graphene.FloatField)
 | 
			
		||||
    assert_conversion(models.FloatField, graphene.Float)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_manytomany_convert_connectionorlist():
 | 
			
		||||
    graphene_type = convert_django_field(Reporter._meta.local_many_to_many[0])
 | 
			
		||||
    assert isinstance(graphene_type, ConnectionOrListField)
 | 
			
		||||
    assert isinstance(graphene_type.field_type, DjangoModelField)
 | 
			
		||||
    assert graphene_type.field_type.model == Reporter
 | 
			
		||||
    assert isinstance(graphene_type.type, DjangoModelField)
 | 
			
		||||
    assert graphene_type.type.model == Reporter
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_manytoone_convert_connectionorlist():
 | 
			
		||||
    graphene_type = convert_django_field(Reporter.articles.related)
 | 
			
		||||
    assert isinstance(graphene_type, ConnectionOrListField)
 | 
			
		||||
    assert isinstance(graphene_type.field_type, DjangoModelField)
 | 
			
		||||
    assert graphene_type.field_type.model == Article
 | 
			
		||||
    assert isinstance(graphene_type.type, DjangoModelField)
 | 
			
		||||
    assert graphene_type.type.model == Article
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_onetoone_convert_model():
 | 
			
		||||
    field = assert_conversion(models.OneToOneField, DjangoModelField, Article)
 | 
			
		||||
    assert field.model == Article
 | 
			
		||||
    assert field.type.model == Article
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_should_foreignkey_convert_model():
 | 
			
		||||
    field = assert_conversion(models.ForeignKey, DjangoModelField, Article)
 | 
			
		||||
    assert field.model == Article
 | 
			
		||||
    assert field.type.model == Article
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,8 @@
 | 
			
		|||
 | 
			
		||||
from graphene import Schema
 | 
			
		||||
from graphene.contrib.django.types import DjangoInterface, DjangoNode
 | 
			
		||||
from graphene.core.fields import IntField
 | 
			
		||||
from graphene.core.fields import IntField, Field
 | 
			
		||||
from graphene.core.types.scalars import String, Int
 | 
			
		||||
from graphene.relay.fields import GlobalIDField
 | 
			
		||||
from graphql.core.type import GraphQLInterfaceType, GraphQLObjectType
 | 
			
		||||
from tests.utils import assert_equal_lists
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +58,8 @@ def test_node_idfield():
 | 
			
		|||
 | 
			
		||||
def test_node_replacedfield():
 | 
			
		||||
    idfield = Human._meta.fields_map['pub_date']
 | 
			
		||||
    assert isinstance(idfield, IntField)
 | 
			
		||||
    assert isinstance(idfield, Field)
 | 
			
		||||
    assert schema.T(idfield).type == schema.T(Int())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_interface_resolve_type():
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user