graphql-python / graphql-core-legacy

GraphQL base implementation for Python (legacy version – see graphql-core for the current one)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error serializing field duration = models.DurationField()?

dionyself opened this issue · comments

Hi there, i'm not 100% sure if this is a bug or not (I'm newbee here) but i got a problem while querying a Node that uses the field type models.DurationField ( it really returns datetime.timedelta).

Traceback (most recent call last):
  File "/tmp/leaky_venv/lib/python3.6/site-packages/promise/promise.py", line 65, in try_catch
    return (handler(*args, **kwargs), None)
  File "/tmp/leaky_venv/lib/python3.6/site-packages/graphql/execution/executor.py", line 375, in <lambda>
    resolved
  File "/tmp/leaky_venv/lib/python3.6/site-packages/graphql/execution/executor.py", line 399, in complete_value
    return complete_leaf_value(return_type, result)
  File "/tmp/leaky_venv/lib/python3.6/site-packages/graphql/execution/executor.py", line 440, in complete_leaf_value
    return return_type.serialize(result)
  File "/tmp/leaky_venv/lib/python3.6/site-packages/graphql/type/scalars.py", line 51, in coerce_float
    return float(value)
TypeError: float() argument must be a string or a number, not 'datetime.timedelta'

This error points to line 51 but i think the class GraphQLScalarType (on line 65) is also related.

Here is my env's prop

PostgreSQL 10.0 on x86_64-pc-linux-gnu (xubuntu 16.04), compiled by gcc (Debian 6.3.0-18) 6.3.0 20170516, 64-bit

Python == 3.6.1

Django==1.11.6
django-filter==1.1.0
graphene==2.0
graphene-django==2.0.0
graphql-core==2.0
graphql-relay==0.4.5

How to reproduce?

1- Create your model

class Asset(models.Model):
    duration = models.DurationField(null=True, blank=True, help_text="Duration of a given offer/product (auto calculated)")
   
    class Meta:
        ordering = ["id"]

2-Create your schema

class AssetNode(DjangoObjectType):

    class Meta:
        model = Asset
        interfaces = (relay.Node, )

3- insert a not-null value on the duration field... and run your query.

{assets(first:20,) {
  edges {
    node {
      id
      duration
    }
  }
}}

and you should que the error:

{
      "message": "float() argument must be a string or a number, not 'datetime.timedelta'"
    }

@dionyself looks like a graphene-django issue but since you're here I'll try and help.

I think the issue is that graphene-django tries to convert the DurationField to a Float graphql type (code is here: https://github.com/graphql-python/graphene-django/blob/b54e02c9ba5925a116a56786897a5d3d33c68dfd/graphene_django/converter.py#L119) but a timedelta can't be converted so simply.

What you probably want to do is update your AssetNode definition to:

class AssetNode(DjangoObjectType):
    def resolve_duration(self, info):
        return self.duration.total_seconds()

    class Meta:
        model = Asset
        interfaces = (relay.Node, )

Thank's for your help, i was using this workaround https://github.com/dionyself/leaky/blob/master/warehouses/schema/query/asset.py#L10
duration = graphene.String() this output looks human readable. now let's check graphene_django repo thank you again.