【问题标题】:SQLAlchemy filter_by query failing when float used使用浮点数时 SQLAlchemy filter_by 查询失败
【发布时间】:2019-09-26 16:57:24
【问题描述】:

我有一个模型定义如下:

class EnergyProfiles(db.Model):
    __tablename__ = "energy_profiles"
    id = db.Column(db.Integer, primary_key=True)
    device_id = db.Column(db.String(64), index=True, unique=False, nullable=False)
    device_hardware = db.Column(db.String(64), index=True, unique=False, nullable=False)
    location = db.Column(db.String(64), index=True, unique=False, nullable=False)
    time = db.Column(db.String(64), index=True, unique=False, nullable=False)
    accompanied = db.Column(db.Boolean)
    wellbeing = db.Column(db.String(64), index=True, unique=False, nullable=False)
    battery = db.Column(db.Integer, index=True, unique=False, nullable=False)

当我通过 API 添加新对象时,我想检查新对象(post_data)是否不存在。这个检查很容易

energy_profile_existing = EnergyProfiles.query.filter_by(**post_data).first()

然而,在将battery 列类型从db.Integer 更改为db.ARRAY(db.Float()) 之后,之前的query.filter_by 失败并出现postgres 错误(忽略下面的user 文本,它是docker compose 输出日志)

 operator does not exist: double precision[] = numeric[]
user_1           | LINE 3: WHERE energy_profiles.battery = ARRAY[0.1,20.1]
user_1           |                                       ^
user_1           | HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.

post_data 包含 battery 作为 JSON 对象的一部分,例如

{
    "device_id": "CP99",
    "device_hardware": "Pycom",
    "location": "irregular",
    "time": "daytime",
    "accompanied": false,
    "wellbeing": "ok",
    "battery": [0.11, 35.22]
}

【问题讨论】:

  • 根据错误消息,我猜测您的数据库中的数组值存储为双精度,但 sqlalchemy 将您的 json 对象中的数组值解释为数字。您可以通过将数组转换为数字(但这会使您的过滤器语法有点复杂)或将您的 db 数组列转换为数字数组来解决此问题。
  • @benvc 不是 SQLA,而是 Postgres 本身,当传递一个数字常量数组(ARRAY[0.1, 20.1])时:“一个数字常量……;否则它被认为是类型numeric。包含小数点和/或指数的常量最初总是假定为 numeric 类型。"

标签: python postgresql sqlalchemy flask-sqlalchemy


【解决方案1】:

正如@benvc 和@IljaEverilä 所指出的,当您传递一个没有任何包含非整数数字常量的显式转换的数组时,假定它们是numeric 类型。

您可以做的是cast the array's contentsfloat,为此您可以使用array([]) 文字来声明数组,并使用数据类型将cast() 声明为ARRAY(Float)

{
    "device_id": "CP99",
    "device_hardware": "Pycom",
    "location": "irregular",
    "time": "daytime",
    "accompanied": false,
    "wellbeing": "ok",
    "battery": cast(array([0.11, 35.22]), ARRAY(Float))
}

【讨论】:

  • 很有魅力,感谢您(以及@benvc 和@IljaEverilä)的出色解释!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-08
  • 1970-01-01
  • 2015-07-05
  • 2019-04-16
  • 2011-03-17
  • 1970-01-01
相关资源
最近更新 更多