diff --git a/graphene/contrib/django/compat.py b/graphene/contrib/django/compat.py index a5b444c7..306b46b3 100644 --- a/graphene/contrib/django/compat.py +++ b/graphene/contrib/django/compat.py @@ -1,15 +1,24 @@ from django.db import models + +class MissingType(object): + pass + try: UUIDField = models.UUIDField except AttributeError: # Improved compatibility for Django 1.6 - class UUIDField(object): - pass + UUIDField = MissingType try: from django.db.models.related import RelatedObject except: # Improved compatibility for Django 1.6 - class RelatedObject(object): - pass + RelatedObject = MissingType + + +try: + # Postgres fields are only available in Django 1.8+ + from django.contrib.postgres.fields import ArrayField, HStoreField, JSONField +except ImportError: + ArrayField, HStoreField, JSONField = (MissingType, ) * 3 diff --git a/graphene/contrib/django/converter.py b/graphene/contrib/django/converter.py index 85cf9049..6fd84e99 100644 --- a/graphene/contrib/django/converter.py +++ b/graphene/contrib/django/converter.py @@ -1,8 +1,9 @@ from django.db import models +from ...core.types.definitions import List from ...core.types.scalars import ID, Boolean, Float, Int, String from ...core.classtypes.enum import Enum -from .compat import RelatedObject, UUIDField +from .compat import RelatedObject, UUIDField, ArrayField, HStoreField, JSONField from .utils import get_related_model, import_single_dispatch singledispatch = import_single_dispatch() @@ -33,6 +34,8 @@ def convert_django_field(field): @convert_django_field.register(models.GenericIPAddressField) @convert_django_field.register(models.FileField) @convert_django_field.register(UUIDField) +@convert_django_field.register(HStoreField) +@convert_django_field.register(JSONField) def convert_field_to_string(field): return String(description=field.help_text) @@ -89,3 +92,9 @@ def convert_relatedfield_to_djangomodel(field): def convert_field_to_djangomodel(field): from .fields import DjangoModelField return DjangoModelField(get_related_model(field), description=field.help_text) + + +@convert_django_field.register(ArrayField) +def convert_field_to_list(field): + base_type = convert_django_field(field.base_field) + return List(base_type, description=field.help_text) diff --git a/graphene/contrib/django/tests/test_converter.py b/graphene/contrib/django/tests/test_converter.py index 938e5556..a22dfbae 100644 --- a/graphene/contrib/django/tests/test_converter.py +++ b/graphene/contrib/django/tests/test_converter.py @@ -1,11 +1,13 @@ +import pytest from django.db import models from py.test import raises import graphene -from graphene.contrib.django.converter import ( +from ..converter import ( convert_django_field, convert_django_field_with_choices) -from graphene.contrib.django.fields import (ConnectionOrListField, - DjangoModelField) +from ..fields import (ConnectionOrListField, + DjangoModelField) +from ..compat import MissingType, ArrayField, HStoreField, JSONField from .models import Article, Reporter @@ -144,3 +146,32 @@ def test_should_onetoone_convert_model(): def test_should_foreignkey_convert_model(): field = assert_conversion(models.ForeignKey, DjangoModelField, Article) assert field.type.model == Article + + +@pytest.mark.skipif(ArrayField is MissingType, + reason="ArrayField should exist") +def test_should_postgres_array_convert_list(): + field = assert_conversion(ArrayField, graphene.List, models.CharField(max_length=100)) + assert isinstance(field.type, graphene.List) + assert isinstance(field.type.of_type, graphene.String) + + +@pytest.mark.skipif(ArrayField is MissingType, + reason="ArrayField should exist") +def test_should_postgres_array_multiple_convert_list(): + field = assert_conversion(ArrayField, graphene.List, ArrayField(models.CharField(max_length=100))) + assert isinstance(field.type, graphene.List) + assert isinstance(field.type.of_type, graphene.List) + assert isinstance(field.type.of_type.of_type, graphene.String) + + +@pytest.mark.skipif(HStoreField is MissingType, + reason="HStoreField should exist") +def test_should_postgres_hstore_convert_string(): + assert_conversion(HStoreField, graphene.String) + + +@pytest.mark.skipif(JSONField is MissingType, + reason="JSONField should exist") +def test_should_postgres_json_convert_string(): + assert_conversion(JSONField, graphene.String) diff --git a/setup.py b/setup.py index 88af1f62..a4923e8d 100644 --- a/setup.py +++ b/setup.py @@ -65,6 +65,8 @@ setup( 'sqlalchemy', 'sqlalchemy_utils', 'mock', + # Required for Django postgres fields testing + 'psycopg2', ], extras_require={ 'django': [