# \`DjangoJSONEncoder\` encodes the \`Decimal\` type as strings

**URL:** <https://forum.djangoproject.com/t/djangojsonencoder-encodes-the-decimal-type-as-strings/41736>\
**Category:** Django Internals\
**Created:** [July 9, 2025, 8:17am UTC](https://forum.djangoproject.com/t/djangojsonencoder-encodes-the-decimal-type-as-strings/41736 "2025-07-09T08:17:47Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![pcouy](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/pcouy/32/29133_2.png) [@pcouy](https://forum.djangoproject.com/u/pcouy)\
**Post date:** [July 9, 2025, 8:17am UTC](https://forum.djangoproject.com/t/djangojsonencoder-encodes-the-decimal-type-as-strings/41736/1 "2025-07-09T08:17:47Z")

</div>

Hello,

While trying to manipulate some data using the `json_script` template filter, I stumbled upon an especially unpleasant to debug situation : after parsing the generated JSON in JS and trying to compare `Decimal` values, I noticed they were encoded as strings, which caused `"10"<"2"` to be true. It took me a while to notice that they were strings, and wrapping the values in `float(...)` before adding them to the encoded dictionnary solved the issue.

Digging into Django’s code base, I found the following lines which make me think this has been done on purpose.

> <https://github.com/django/django/blob/6df19412aabb7d969f5eab4b2ff41269de89b233/django/core/serializers/json.py#L110-L111>

Does anyone know the original reasoning behind this behavior ? Should I open a ticket for this to be changed in a future major version ?

---

<div class="post-metadata">

**Author:** ![sevdog](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sevdog/32/20692_2.png) [@sevdog](https://forum.djangoproject.com/u/sevdog)\
**Post date:** [July 9, 2025, 8:39am UTC](https://forum.djangoproject.com/t/djangojsonencoder-encodes-the-decimal-type-as-strings/41736/2 "2025-07-09T08:39:30Z")

</div>

Just a guess, it could be because:

> The [`decimal`](https://docs.python.org/3/library/decimal.html#module-decimal) module provides support for fast correctly rounded decimal floating-point arithmetic. It offers several advantages over the [`float`](https://docs.python.org/3/library/functions.html#float) datatype: […]

Representing a `Decimal` as a `float` would cause it to lose precision, which is the reason that class/module exists.

The only way to keep precision and to represent a `Decimal` in JSON is to convert it to a string. It is up to you to convert it back to `Decimal`, because it is not a native JSON type.

---

<div class="post-metadata">

**Author:** ![adamchainz](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/adamchainz/32/26_2.png) [@adamchainz](https://forum.djangoproject.com/u/adamchainz)\
**Post date:** [July 9, 2025, 9:31am UTC](https://forum.djangoproject.com/t/djangojsonencoder-encodes-the-decimal-type-as-strings/41736/3 "2025-07-09T09:31:39Z")

</div>

> [@pcouy](#):
>
> Does anyone know the original reasoning behind this behavior ? Should I open a ticket for this to be changed in a future major version ?

It’s totally on purpose. The [`json_script` function docs](https://docs.djangoproject.com/en/5.2/ref/utils/#django.utils.html.json_script) state that it uses `DjangoJSONEncoder`, which has its own documentation of the behaviour.

I think what’s missing here is a link from [the `json_script` template filter](https://docs.djangoproject.com/en/5.2/ref/templates/builtins/#json-script) to the function docs.

The reason that `DjangoJSONEncoder` exists is to support serialization of more field types, as Python’s built-in serializer will error for `Decimal`s, `date`s, and other types common to Django.

If you load an arbitrary `Decimal` value as a JavaScript number, it can lose data, as JS only supports floating point numbers, which have much less precision. It’s possible to load a decimal library in JS to retain precision. Otherwise, if you can live with the imprecision of floats, you can try JS numbers.
