浮点格式JSON转储与Python和Google应用程序引擎问题
我目前正在使用python并在Google App Engine上创建一个简单的API,允许用户通过使用命令行进行API调用来使用GET、POST、DELETE和PUT动词。我使用curl通过API调用来操作数据。我已经能够成功地添加数据并将其显示回来,但问题是我有一个“price”属性,该价格以浮点形式存储在GAE(Google App Engine)上的数据存储中,数字在提交时格式化,但当JSON显示数据存储中的内容时,它的格式不同。例如,JSON响应显示8.990000000000002。我很确定这不是GAE问题,而是JSON问题 问题示例:浮点格式JSON转储与Python和Google应用程序引擎问题,python,json,google-app-engine,webapp2,Python,Json,Google App Engine,Webapp2,我目前正在使用python并在Google App Engine上创建一个简单的API,允许用户通过使用命令行进行API调用来使用GET、POST、DELETE和PUT动词。我使用curl通过API调用来操作数据。我已经能够成功地添加数据并将其显示回来,但问题是我有一个“price”属性,该价格以浮点形式存储在GAE(Google App Engine)上的数据存储中,数字在提交时格式化,但当JSON显示数据存储中的内容时,它的格式不同。例如,JSON响应显示8.990000000000002。
curl --data "name=t-shirt&description=Star Trek&price=8.99&user=test1" -H "Accept: application/json" https://mywebsite.appspot.com/product
正确存储在数据存储中,但返回JSON,如下所示:
{"description": "Star Trek", "price": 8.9900000000000002, "name": "t-shirt", "user": "test1", "key": 5206065687822336}
这是我的模特
from google.appengine.ext import ndb
class Model(ndb.Model):
def to_dict(self):
d = super(Model, self).to_dict()
d['key'] = self.key.id()
return d
class User(Model):
username = ndb.StringProperty(required=True)
password = ndb.StringProperty(required=True)
class Product(Model):
name = ndb.StringProperty(required=True)
description = ndb.StringProperty(required=True)
price = ndb.FloatProperty()
color = ndb.StringProperty()
size = ndb.StringProperty()
user = ndb.StringProperty(required=True)
class Sales(Model):
products = ndb.KeyProperty(repeated=True)
datetime = ndb.DateTimeProperty(required=True)
quantity = ndb.IntegerProperty(repeated=True)
product_cost = ndb.FloatProperty(repeated=True)
total_cost = ndb.FloatProperty()
latitude = ndb.FloatProperty()
longitude = ndb.FloatProperty()
user = ndb.KeyProperty(required=True)
def to_dict(self):
d = super(Sales, self).to_dict()
d['products'] = [i.id() for i in d['products']]
return d
下面是product.py:
import webapp2
from google.appengine.ext import ndb
import models
import json
class Product(webapp2.RequestHandler):
#Create a Product entity
def post(self):
if 'application/json' not in self.request.accept:
self.response.status = 406
self.response.status_message = 'Not acceptable, API only supports application/json MIME type.'
return
new_product = models.Product()
name = self.request.get('name', default_value=None)
description = self.request.get('description', default_value=None)
price = self.request.get('price', default_value=0)
color = self.request.get('color', default_value=None)
size = self.request.get('size', default_value=None)
user = self.request.get('user', default_value=None)
if name:
new_product.name = name
else:
self.response.status = 400
self.response.status_message = 'Invalid request, name required'
if description:
new_product.description = description
else:
self.response.status = 400
self.response.status_message = 'Invalid request, description required'
if price:
new_product.price = float(price)
if color:
new_product.color = color
if size:
new_product.size = size
if user:
new_product.user = user
else:
self.response.status = 400
self.response.status_message = 'Invalid request, username required'
key = new_product.put()
out = new_product.to_dict()
self.response.write(json.dumps(out))
return
#Return an Product entity
def get(self, **kwargs):
if 'application/json' not in self.request.accept:
self.response.status = 406
self.response.status_message = 'Not acceptable, API only supports application/json MIME type.'
self.response.write(self.response.status_message)
return
#Return selected product details
if 'id' in kwargs:
out = ndb.Key(models.Product, int(kwargs['id'])).get().to_dict()
self.response.write(json.dumps(out))
#Return all product ids
else:
q = models.Product.query()
keys = q.fetch(keys_only=False)
results = {x.key.id() : x.to_dict() for x in keys}
self.response.write(json.dumps(results))
我为我的过度行为道歉,但我想确保所有东西都可以看到。任何帮助都将不胜感激。我看过一些类似的项目,但我在这里使用字典的方式,我似乎无法得到正确的格式
提前谢谢你 我认为这实际上不是一个问题。如果你想了解为什么会出现这种年久失修的情况,你可能需要阅读维基百科的文章。TLDR是指在0和1之间已经有无限多个有理数,但计算机只能存储有限数量的数据。更重要的是,您通常希望将实数存储在32位(单)或64位(双)数据中,以实现高效计算。因此,机器编号只是实数的一个子集,通常必须四舍五入到最接近的机器编号。如果圆点总是在同一个位置,并且您使用的是以10为基数的数字,这样您就知道舍入“8.99”时没有错误,但对于IEEE 754中定义的普通浮点数,情况并非如此 基本上8.99=8.990000000000002在这里成立 您有几种解决问题的方法: 1) 不要解决问题,只需对显示的值进行四舍五入即可 警告:这可能不是您想要的。
通常可以在显示时对错误进行四舍五入,因为通常错误非常小,例如在游戏中,这可能是可以接受的。然而,在这种情况下,您似乎正在创建一个商店,如果在不同的地方有不同的环形交叉口,则可能会出现问题。例如,在某些情况下,可能会在订单上产生0.01的差异,从而导致各种问题。不要用浮点数存储价格/金额 2) 使用整数值[这里可能是最好的选择] 将899存储为数据库中的整数,而不是存储8.99。如果只使用加法/减法,整数算术就没有舍入问题 这可能有点不方便,因为它将涉及更新数据库和显示数字(即,您必须在正确的位置插入一个点)。但这很可能是你拥有的最安全的赌注,如果你没有专门的号码,这通常被认为是一个好的选择 3) 使用具有正确基础的定点数字 如果你对这些数字做了大量的算术运算,那么使用定点数字库可能会更方便,并且基本上可以为你的问题使用定制的有理数表示法。它基本上与选项2相同,但您并不是自己实现所有功能,而是具有更大的灵活性。然而,我个人会选择选项2,因为我不知道是否有这样一个库可以在Python和Javascript中使用,而且它可能只涉及对项目的不必要的依赖