Repository: graphql-python/graphene-django

Issue:
Convert DecimalField to String rather than Float
DecimalField entries are currently being converted to Float (https://github.com/graphql-python/graphene-django/blob/8f5a425859ea380d0640c441c5c7f3b1acae17b4/graphene_django/form_converter.py#L56-L59)

Full support for Decimal would be great, but in the meantime I propose that DecimalField should be converted to String instead. Once you've converted a Decimal to a Float, you've probably lost the benefit of why you used Decimal in the first place, since you'll now have values like `3.14000000000000012`, rather than `3.14`. If it is converted to String, it is simple enough for the user to convert that String back to Decimal, whereas converting from Float to Decimal is not straightforward.


Discussion:
As a workaround for this particular problem, I created a Decimal type, and then am explicitly setting that field in the DjangoObjectType class.  For example, I created a Decimal type like this

```
import decimal

from graphene.types import Scalar
from graphql.language import ast

class Decimal(Scalar):
    """ 
    The `Decimal` scalar type represents a python Decimal.
    """
    @staticmethod
    def serialize(dec):
        assert isinstance(dec, decimal.Decimal), (
            'Received not compatible Decimal "{}"'.format(repr(dec))
        )
        return str(dec)
    
    @staticmethod
    def parse_value(value):
        return decimal.Decimal(value)
    
    @classmethod
    def parse_literal(cls, node):
        if isinstance(node, ast.StringValue):
            return cls.parse_value(node.value)

```

and then explicitly replace the field like this:
```
class MyModelType(DjangoObjectType):
    my_decimal_field = Decimal()
    class Meta:
        model = MyModel
```
assuming that I have a Django model _MyModel_ with Decimal field _my_decimal_field_.

Decimal type landed in graphene: https://github.com/graphql-python/graphene/issues/703

Edit: Appears it isn't released yet but is merged, need graphene>2.1.3
Yeah, I finally got around to adding my Decimal type into graphene.   It should be possible to fix graphene-django's implementation of DecimalField after the next release of graphene to actually use a Decimal, and it won't be necessary to convert to a **String** (as per the title of this issue).  Note that the JSON output is implemented as string though.
Brilliant, thank you @picturedots!
@gsvr  I didn't make the graphene-django change that you noted in form_converter.py above, so not sure if this is issue should be closed.  Without that change, it looks like Decimals are still explicitly converted to floats.
Waiting on this feature as well.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@gsvr @jkimbo Is this still relevant?
The issue is still relevant. We talked with @jkimbo about how to fix it. My work will be on https://github.com/graphql-python/graphene-django/pull/958 and i hope to complete in next couple days.
Thanks @ulgens 
I agree that it's still relevant - I've used a workaround in the meantime but this would be a good general improvement imho
Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

Resolving patch:
diff --git a/graphene_django/forms/converter.py b/graphene_django/forms/converter.py
--- a/graphene_django/forms/converter.py
+++ b/graphene_django/forms/converter.py
@@ -1,12 +1,23 @@
 from django import forms
 from django.core.exceptions import ImproperlyConfigured
 
-from graphene import ID, Boolean, Float, Int, List, String, UUID, Date, DateTime, Time
+from graphene import (
+    Boolean,
+    Date,
+    DateTime,
+    Decimal,
+    Float,
+    ID,
+    Int,
+    List,
+    String,
+    Time,
+    UUID,
+)
 
 from .forms import GlobalIDFormField, GlobalIDMultipleChoiceField
 from ..utils import import_single_dispatch
 
-
 singledispatch = import_single_dispatch()
 
 
@@ -52,6 +63,10 @@ def convert_form_field_to_nullboolean(field):
 
 
 @convert_form_field.register(forms.DecimalField)
+def convert_field_to_decimal(field):
+    return Decimal(description=field.help_text, required=field.required)
+
+
 @convert_form_field.register(forms.FloatField)
 def convert_form_field_to_float(field):
     return Float(description=field.help_text, required=field.required)
diff --git a/graphene_django/rest_framework/serializer_converter.py b/graphene_django/rest_framework/serializer_converter.py
--- a/graphene_django/rest_framework/serializer_converter.py
+++ b/graphene_django/rest_framework/serializer_converter.py
@@ -110,8 +110,12 @@ def convert_serializer_field_to_bool(field):
     return graphene.Boolean
 
 
-@get_graphene_type_from_serializer_field.register(serializers.FloatField)
 @get_graphene_type_from_serializer_field.register(serializers.DecimalField)
+def convert_serializer_field_to_decimal(field):
+    return graphene.Decimal
+
+
+@get_graphene_type_from_serializer_field.register(serializers.FloatField)
 def convert_serializer_field_to_float(field):
     return graphene.Float
 


Test patch:
diff --git a/graphene_django/filter/tests/test_fields.py b/graphene_django/filter/tests/test_fields.py
--- a/graphene_django/filter/tests/test_fields.py
+++ b/graphene_django/filter/tests/test_fields.py
@@ -5,7 +5,7 @@
 from django.db.models import TextField, Value
 from django.db.models.functions import Concat
 
-from graphene import Argument, Boolean, Field, Float, ObjectType, Schema, String
+from graphene import Argument, Boolean, Decimal, Field, ObjectType, Schema, String
 from graphene.relay import Node
 from graphene_django import DjangoObjectType
 from graphene_django.forms import GlobalIDFormField, GlobalIDMultipleChoiceField
@@ -388,7 +388,7 @@ class Meta:
     field = DjangoFilterConnectionField(ArticleNode, filterset_class=ArticleIdFilter)
     max_time = field.args["max_time"]
     assert isinstance(max_time, Argument)
-    assert max_time.type == Float
+    assert max_time.type == Decimal
     assert max_time.description == "The maximum time"
 
 
@@ -671,7 +671,7 @@ def resolve_all_reporters(self, info, **args):
     schema = Schema(query=Query)
     query = """
         query NodeFilteringQuery {
-            allReporters(limit: 1) {
+            allReporters(limit: "1") {
                 edges {
                     node {
                         id
diff --git a/graphene_django/forms/tests/test_converter.py b/graphene_django/forms/tests/test_converter.py
--- a/graphene_django/forms/tests/test_converter.py
+++ b/graphene_django/forms/tests/test_converter.py
@@ -1,19 +1,19 @@
 from django import forms
 from py.test import raises
 
-import graphene
 from graphene import (
-    String,
-    Int,
     Boolean,
+    Date,
+    DateTime,
+    Decimal,
     Float,
     ID,
-    UUID,
+    Int,
     List,
     NonNull,
-    DateTime,
-    Date,
+    String,
     Time,
+    UUID,
 )
 
 from ..converter import convert_form_field
@@ -97,8 +97,8 @@ def test_should_float_convert_float():
     assert_conversion(forms.FloatField, Float)
 
 
-def test_should_decimal_convert_float():
-    assert_conversion(forms.DecimalField, Float)
+def test_should_decimal_convert_decimal():
+    assert_conversion(forms.DecimalField, Decimal)
 
 
 def test_should_multiple_choice_convert_list():
diff --git a/graphene_django/rest_framework/tests/test_field_converter.py b/graphene_django/rest_framework/tests/test_field_converter.py
--- a/graphene_django/rest_framework/tests/test_field_converter.py
+++ b/graphene_django/rest_framework/tests/test_field_converter.py
@@ -133,9 +133,9 @@ def test_should_float_convert_float():
     assert_conversion(serializers.FloatField, graphene.Float)
 
 
-def test_should_decimal_convert_float():
+def test_should_decimal_convert_decimal():
     assert_conversion(
-        serializers.DecimalField, graphene.Float, max_digits=4, decimal_places=2
+        serializers.DecimalField, graphene.Decimal, max_digits=4, decimal_places=2
     )
 
 
diff --git a/graphene_django/tests/test_converter.py b/graphene_django/tests/test_converter.py
--- a/graphene_django/tests/test_converter.py
+++ b/graphene_django/tests/test_converter.py
@@ -242,7 +242,7 @@ def test_should_float_convert_float():
     assert_conversion(models.FloatField, graphene.Float)
 
 
-def test_should_float_convert_decimal():
+def test_should_decimal_convert_decimal():
     assert_conversion(models.DecimalField, graphene.Decimal)