python - 使用适当的十进制数据类型将 django 中的模型序列化为 json

标签 python django serialization

这是一个示例模型:

class FooModel(models.Model):
    foo = models.DecimalField(max_digits=6, decimal_places=3, null=True)

序列化:

from django.core import serializers
obj = get_object_or_404(FooModel, pk=1)
data = serializers.serialize("json", [obj])

这将返回类似以下内容:

[
    {
        "pk": 1,
        "model": "app.foomodel",
        "fields": {
            "foo": "50"
        }
    }
]

问题

如何使 foo 字段序列化为 float ,而不是字符串。我不想使用 float 模型类型,因为 float 有时不能正确存储小数。

提前谢谢您。

最佳答案

如果该值实际上是 5050.0Decimal 对象保留最初输入的内容,例如Decimal('50') 产生 50

>>> from decimal import Decimal
>>> d = Decimal('50')
>>> print d
50

遗憾的是,提供给 DecimalField 构造函数的参数仅用于限制存储值而不显示它们。

现在,由于 Django 仅使用标准 json/simplejson 库,因此您可以在序列化时指定自定义编码器,如 this question 中建议的那样:

import decimal
import json
class DecimalEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, decimal.Decimal):
            return '%.2f' % obj # Display Decimal obj as float
        return json.JSONEncoder.default(self, obj)

但事情并没有就此结束。如detailed in this blog post ,Django 显式地将 cls=DjangoJSONEncoder 传递给 simplejson.dump(...),因此我们必须通过创建引用 的自定义序列化器对象来规避此问题我们创建的 DecimalEncoder:

from django.core.serializers.json import Serializer as JSONSerializer
class DecimalSerializer(JSONSerializer):
    def end_serialization(self):
        self.options.pop('stream', None)
        self.options.pop('fields', None)
        json.dump(self.objects, self.stream, cls=DecimalEncoder, **self.options)

接下来,将 DecimalSerializer 实例化为您自己的序列化器对象,神奇的事情发生了:

my_serializer = DecimalSerializer()
print my_serializer.serialize([obj], indent=4)

其产量:

[
    {
        "pk": 1, 
        "model": "app.foomodel", 
        "fields": {
            "foo": "50.00"
        }
    }
]

这看起来工作量很大。使用 Django 的 model validation 可能更容易在保存之前确保 FooModel.foo 字段始终是 float 。这是暴力尝试:

from django.core.exceptions import ValidationError

class FooModel(models.Model):
    foo = models.DecimalField(max_digits=6, decimal_places=3, null=True)

    def clean(self):
        if '.' not in str(self.foo):
            raise ValidationError('Input must be float!')

    def save(self, *args, **kwargs):
        self.full_clean()
        super(FooModel, self).save(*args, **kwargs)

然后:

>>> f = FooModel(foo='1')
>>> f.save()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/jathan/sandbox/foo/app/models.py", line 15, in save
    self.full_clean()
  File "/usr/local/lib/python2.6/dist-packages/django/db/models/base.py", line 828, in full_clean
    raise ValidationError(errors)
ValidationError: {'__all__': [u'Input must be float!']}

关于python - 使用适当的十进制数据类型将 django 中的模型序列化为 json,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8235513/

相关文章:

python - 检查用户是否在 Django 模板中订阅了 dj-stripe

python - Kivy DropDown 不受 max_height 的影响

python - 根据指定列中的字符串值条目是否包含子字符串来分隔 pandas 数据框

javascript - 如何过滤掉谷歌表格中的重复项和增量

python - 如何使用 Django REST Framework (DRF) 3 创建 Django 用户

java - java序列化如何解决循环引用问题?

java - 如何将我的自定义对象存储在sql数据库中

python数组作为参数列表

python - 为什么在 Django 中使用线程局部变量不好?

ruby-on-rails - 如何对序列化属性执行包含验证?