SQLAlchemy按PickleType内容过滤查询

时间:2014-04-29 09:25:59

标签: python filter sqlalchemy pickle flask-sqlalchemy

我有这个Meter对象模型

class Meter(db.Model):
    """
    Model for repair meter.

    """
    __tablename__ = 'meters'

    id = db.Column(db.Integer, primary_key=True, nullable=False)
    meter_no = db.Column(db.String(50), unique=True, nullable=False)
    client = db.Column(db.String(50), unique=True, nullable=False)
    problems = db.Column(db.PickleType)
    functional = db.Column(db.Boolean(), default=False, server_default="false")
    location = db.Column(db.Integer, db.ForeignKey('locations.id'))
    date_in = db.Column(db.Date, default=dt.date.today())
    date_out = db.Column(db.Date)

问题PickleType列存储包含Problem对象的ID的Python列表

然后我有这个函数试图查询米数据库表,只获得列表存储中具有特定问题id(prob_id)的Meter对象为PickleType。

def problemrate(prob_id, month):
    """
    Return meters with the problem id for a particular month.

    args:
        prob_id (int): problem id
        month (int): month number e.g. april -> 4

    returns:
        meters (list): list of meter objects

    raises: None

    """
    meters = Meter.query.filter(and_(extract('month', Meter.date_in) == month,
                    prob_id in Meter.problems)).all()

    return meters

然而,在调用函数时我收到错误:

NotImplementedError: Operator 'getitem' is not supported on this expression

按PickleType列的内容过滤sqlalchemy查询的写入方式是什么? 有可能或sqlalchemy不支持这个吗?

1 个答案:

答案 0 :(得分:3)

简短说明:PickleType不支持任何关系功能,例如查询/过滤器。它的目的是存储和检索。请改用sqlalchemy.orm.relationship。

详细解释:错误消息实际上是正确的。过滤器函数中的所有内容都将编译为sql查询,(打印查询以查看此内容),因此' in'运算符不会编译为有效查询,也不会编译任何其他getItem运算符。什么是工作' =='但是为此您需要传递完全相同的对象,以便它可以转换为与存储的对象相同的PickleType对象。比较是在内部完成的。

解决方案:在普通的SQL中,您可以将每个列表项分别存储在不同的表中,并通过id关联。在SQLAlchemy中,您可以执行类似的操作:

from sqlalchemy.orm import relationship
from sqlalchemy.ext.associationproxy import association_proxy

class Meter(db.Model):
    """
    Model for repair meter.

    """
    __tablename__ = 'meters'

    id = db.Column(db.Integer, primary_key=True, nullable=False)
    meter_no = db.Column(db.String(50), unique=True, nullable=False)
    client = db.Column(db.String(50), unique=True, nullable=False)
    meter_problems = relationship('Problem', secondary=lambda: meterproblems_table)
    functional = db.Column(db.Boolean(), default=False, server_default="false")
    location = db.Column(db.Integer, db.ForeignKey('locations.id'))
    date_in = db.Column(db.Date, default=dt.date.today())
    date_out = db.Column(db.Date)

    problems = association_proxy('meter_problems', 'problem')

class Problem(db.Model):
    __tablename__ = 'problem'
    id = db.Column(db.Integer, primary_key=True, nullable=False)
    problem = db.Column('keyword', db.String(64))

    def __init__(self, problem):
        self.problem = problem

meterproblems_table = db.Table(
    'meterproblems',
    db.metadata,
    db.Column(
        'meter_id',
        db.Integer,
        db.ForeignKey("meters.id"),
        primary_key=True
    ),
    db.Column(
        'problem_id',
        db.Integer,
        db.ForeignKey("problem.id"),
        primary_key=True
    )
)

你的查询而不是:

meters = Meter.query.filter(
    extract('month', Meter.date_in) == month,
    Meter.meter_problems.has(keyword=prob_id)
).all()

assocation_proxy用于轻松地将项目添加到meter_problems列:

obj.problems.append('something')

obj是仪表对象。

Doumentation here