在将[Django]模型转为JsonEncode时,想要为日期和数字进行格式设置
我想做的事情
-
- Djangoのモデルをシリアル化(JSON)してクライアントにレスポンスしたい
-
- この時に日付を任意の書式に整形したい(例えば “19/03/01 13:00”)
-
- 数値を書式設定および単位を付与したい(例えば 10000 を “10,000円”とか”10,000部”とか)
- 整形はサーバサイドで実行したい
学科的问题
使用Django提供的序列化器(django.core.serializers.serialize / DjangoJSONEncoder)能够轻松地对Django模型进行序列化,但存在以下问题。
日期时间类型的显示冗长不简洁。
2019-03-06T17:46:04.013Z
只有模型字段需要进行序列化。
同样,它只适用于模型字段。即使准备了格式设置的方法或属性,也不能包括在内。(由于在得出这个无法进行的结论之前进行了一些调查,所以我写了这篇文章。希望能对你有所帮助。)
会包含不必要的信息。
由于包含了模型的字段、名称和主键值,这变得冗余了(这意味着我们需要进行Django依赖的处理来提取客户机需要的数据)。
In [11]: serializers.serialize('json',[os], stream=sys.stdout, indent=2)
[{
"model": "order.ordersummary", ★ここ★
"pk": 1, ★ここ★
"fields": {
・・・
}
}]
应对方法
以下是原文的中文释义:
案1:请用中文重新表达以下句子,只需要提供一个选项:
请提供一种选择。
将公式文件中所述的方法用于以下步骤:
自定义JSON序列化编码器,将其传递给序列化器。
from django.core.serializers.json import DjangoJSONEncoder
class CustomJSONEncoder(DjangoJSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.strftime("%y/%m/%d %H:%M") ★ここ★
return super().default(obj)
from django.core import serializers
serializers.serialize('json', cls=CustomJSONEncoder)
用下面的代码可以更改日期时间格式,但是数值类型(如int)不能通过相同的方式进行更改,而且由于无法控制数据的属性名,因此无法附加”円”或”部”属性。
if isinstance(obj, int):
return "{:,}".format(obj)
以下是案2(最终版本)
在使用Django的序列化器之前,我们可以使用Python的Json序列化器(json.dumps(obj))。
然而,请注意Django模型不能直接进行转换,否则将会导致执行错误。
import json
json.dumps(fooModel)
>> TypeError: Object of type 'FooModel' is not JSON serializable
因此,使用model_to_dict函数将模型转化为字典,并将其序列化。
import json
from django.forms.models import model_to_dict
json.dumps(model_to_dict(FooModel))
然而,当模型包含datetime类型时会导致错误。
TypeError: Object of type 'datetime' is not JSON serializable
为了避免这个问题,将格式转换后的字符串设置给已设定为datetime类型的元素。
from django.forms.models import model_to_dict
class FooModel(models.Model)
updated_at = models.DateTimeField('更新日時', auto_now=True, null=True)
def to_dict(self):
ret = model_to_dict(self) ★この時点では ret['update_at']はdatetime型★
ret['updated_at'] = self.updated_at.strftime("%y/%m/%d %H:%M") ★文字列にしてしまう★
return ret
import json
json.dumps(fooModel.to_dict())
您可以使用相同的方法将数字类型字段转换为任意字符串。
from django.forms.models import model_to_dict
class FooModel(models.Model)
total_charge = models.PositiveIntegerField('合計金額', default=0)
updated_at = models.DateTimeField('更新日時', auto_now=True, null=True)
def to_dict(self):
ret = model_to_dict(self)
ret['total_charge'] = "{:,}円".format(self.total_charge) ★ここ★
ret['updated_at'] = self.updated_at.strftime("%y/%m/%d %H:%M")
return ret
作为这种方法的好处,可以提到的是,响应中不再包含不必要的字段(模型名称,主键值)。
额外的东西
另外,如果有多个模型实例,编写重复执行to_dict()的代码会变得冗长。
通过将自定义的Json序列化器传递给json.dumps,可以像下面的文章中所述一样实现无冗长描述。
对于在Django中使用JSON的思考以及SQL优化等的一项研究 – 全球
from django.db import models as django_models
from django.db.models.query import QuerySet
class CustomJSONEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, django_models.Model) and hasattr(obj, 'to_dict'):
return obj.to_dict()
if isinstance(obj, QuerySet):
return list(obj)
json.JSONEncoder.default(self, obj)
from <...> import CustomJSONEncoder
json.dumps(model_list, cls=CustomJSONEncoder)
这就是以上内容。
如果实现的太过冗长,会有一点多余的感觉。
希望在Django的序列化器选项中能够添加模型的方法和属性作为序列化对象。(听说Django Rest framework可以实现这个功能,如果有余力的话,可以去看看实现方法…)