Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
浮点格式JSON转储与Python和Google应用程序引擎问题_Python_Json_Google App Engine_Webapp2 - Fatal编程技术网

浮点格式JSON转储与Python和Google应用程序引擎问题

浮点格式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。

我目前正在使用python并在Google App Engine上创建一个简单的API,允许用户通过使用命令行进行API调用来使用GET、POST、DELETE和PUT动词。我使用curl通过API调用来操作数据。我已经能够成功地添加数据并将其显示回来,但问题是我有一个“price”属性,该价格以浮点形式存储在GAE(Google App Engine)上的数据存储中,数字在提交时格式化,但当JSON显示数据存储中的内容时,它的格式不同。例如,JSON响应显示8.990000000000002。我很确定这不是GAE问题,而是JSON问题

问题示例:

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中使用,而且它可能只涉及对项目的不必要的依赖