Graphene-django: Registering additional types

Created on 12 Oct 2016  路  10Comments  路  Source: graphql-python/graphene-django

Currently, only built in model field types are supported.

If you try to use alternative field types (such as currency fields provided by https://github.com/django-money/django-money), they cause this error:

web_1  |   File "/usr/local/lib/python3.5/site-packages/graphene_django/converter.py", line 58, in convert_django_field
web_1  |     (field, field.__class__))
web_1  | Exception: Don't know how to convert the Django field renting.RenterProfile.phone_number (<class 'phonenumber_field.modelfields.PhoneNumberField'>)

There should probably be some API exposed to register conversions for additional field types. (Or if this is already possible, explain it in the docs.)

Most helpful comment

@reinierpd
I was getting this error and as a workaround I had to import my schema only after registering my CustomField converter.

If I put this line import cookbook.schema in the imports section the will raise the error again.

import graphene
from graphene_django.converter import convert_django_field, convert_field_to_string
from geoposition.fields import GeopositionField

@convert_django_field.register(GeopositionField)
def convert_geofield_to_string(field, registry=None):
     return graphene.String(description=field.help_text, required=not field.null)

import cookbook.schema

class Query(cookbook.schema.Query, graphene.ObjectType):
    # This class extends all abstract apps level Queries and graphene.ObjectType
    pass

schema = graphene.Schema(query=Query)

All 10 comments

I think I found a solution registering the custom field in schema.py immediately below the last import. F.i. if you need to register CustomField in the cookbook example you should have something like this:

import cookbook.ingredients.schema
import graphene
from graphene_django.converter import convert_django_field

from graphene_django.debug import DjangoDebug

@convert_django_field.register(CustomField)
def my_convert_function(field, registry=None):
    # Customization here
    return something


class Query(cookbook.ingredients.schema.Query, graphene.ObjectType):
    debug = graphene.Field(DjangoDebug, name='__debug')


schema = graphene.Schema(query=Query)

It seems working, but since there's no documentation about this it could be terribly wrong.

The solution proposed by @marbont would definitely work.
However I think we should choose an approach similar to Django Admin formfield_overrides.

Probably having something like:

def convert_phonenumberfield(field, registry=None):
    return graphene.String()

class Transaction(DjangoObjectType):
    class Meta:
        model = TransactionModel
        field_overrides = {
            MoneyField: graphene.String,
            # Also accepts a function for conversion
            PhoneNumberField: convert_phonenumberfield
        }

Thoughs?

@syrusakbary I don't really like that approach, namely because it would mean I need to set field_overrides for every model in my schema where I use a non-standard field: very un-DRY. Ideally, other libraries (which furnish custom fields) should be able to automatically handle registration. It seems like I should only have to say how to convert a certain field type once.

Sounds reasonable.

I would go with the solution provided by @marbont then:

import graphene
from graphene_django.converter import convert_django_field

@convert_django_field.register(CustomField)
def my_convert_function(field, registry=None):
    return graphene.String()

If you think we should provide a cleaner API for registering field conversion, any ideas will be welcome!

Once we agree on a way for registering, we can make it official by having a page on the docs with the recommended way to add additional types.

@syrusakbary Should that be working as is? Somehow I had problems with it, but I can take a look again.

As long as is the "register" happens before the creation of a DjangoObjectType we should be covered.

However if you see any issue with that just ping here and we can work on it! :)

Hi i have the same issue and i added this to the schema.py :

from graphene_django.converter import convert_django_field
from phonenumber_field.modelfields import PhoneNumberField

@convert_django_field.register(PhoneNumberField)
def convert_phone_number_to_string(field, registry=None):
    return graphene.String( description=field.help_text, required=not field.null)

but i got the same :
"Don't know how to convert the Django field paid_ads.Client.phone ()"
I did'nt found any doc for this. Can anyone explain how to register a new type? Thanx

@reinierpd
I was getting this error and as a workaround I had to import my schema only after registering my CustomField converter.

If I put this line import cookbook.schema in the imports section the will raise the error again.

import graphene
from graphene_django.converter import convert_django_field, convert_field_to_string
from geoposition.fields import GeopositionField

@convert_django_field.register(GeopositionField)
def convert_geofield_to_string(field, registry=None):
     return graphene.String(description=field.help_text, required=not field.null)

import cookbook.schema

class Query(cookbook.schema.Query, graphene.ObjectType):
    # This class extends all abstract apps level Queries and graphene.ObjectType
    pass

schema = graphene.Schema(query=Query)

Hello! I'm building a photo library site and use django-imagekit package, which has imagekit.models.ImageSpecField to represent processed-on-demand version of django.db.models.ImageField.

In models.py I have:

class Photo(models.Model):
    img = models.ImageField(upload_to='images')
    thumb = ImageSpecField(source='img', processors=[ResizeToFit(100,100)])

In schema.py:
```
@converter_django_field.register(ImageSpecField)
def convert_ImageSpecField(field, registry=None):
return graphene.String()

class PhotoType(DjangoObjectType):
class Meta:
model = Photo

def resolve_img(self, *_):
    return '{}{}'.format(MEDIA_URL, self.img)

class Query(graphene.AbstractType):
photos = graphene.List(PhotoType)

def resolve_photos(self, *_):
    return Photo.objects.all()

````

When I query for {photos{img}}, I get what I expect: relative urls of img fields.
But when I ask for {photos{thumb}}, I get error message: "Cannot query field \"thumb\" on type \"PhotoType\".". And thumb field is not present when I browse API in GraphiQL.

Did I do it wrong? Is it possible to do?

fix:

  • ref #303
from phonenumber_field.modelfields import PhoneNumberField

@convert_django_field.register(PhoneNumberField)
def convert_phonenumberfield(field, registry=None):
    return graphene.String()


  • this is ok for me.
Was this page helpful?
0 / 5 - 0 ratings

Related issues

khankuan picture khankuan  路  4Comments

nickhudkins picture nickhudkins  路  3Comments

amiyatulu picture amiyatulu  路  3Comments

MythicManiac picture MythicManiac  路  3Comments

ZuluPro picture ZuluPro  路  3Comments