【发布时间】:2019-08-22 18:18:45
【问题描述】:
我一直在尝试编写一些具有混合属性的表达式,但我发现它们非常有限,我想知道我是否可以绕过这些限制。
基本上,我发现它们可以与 session.query(Model.hybrid_property) 或 session.query(Model).filter(Model.hybrid_property==x) 一起使用,但不能同时使用。
这是我的意思的一个例子,假设有两行称为value1 和value2,name 是hybrid_property。
# With as_scalar()
>>> session.query(Model).filter(Model.value=='value1').all()
[([<__main__.Model object],)] # this is wanted
>>> session.query(Model.value).all()
[(u'value1',)]
# Without as scalar()
>>> session.query(Model).filter(Model.value=='value1').all()
[]
>>> session.query(Model.value).all()
[(u'value1',), (u'value2',)] # this is wanted
根据是否使用as_scalar(),它会改变它的作用。有没有办法让它同时工作?
这是一些示例代码(经过编辑以显示完全不起作用的示例):
import os
from sqlalchemy import create_engine, Column, Integer, String, select, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import sessionmaker, relationship
Engine = create_engine('sqlite://')
Base = declarative_base(bind=Engine)
Session = sessionmaker(bind=Base.metadata.bind)
class ModelRelation(Base):
__tablename__ = 'ModelRelation'
row_id = Column(Integer, primary_key=True)
name = Column(String(64))
class Model(Base):
__tablename__ = 'Model'
row_id = Column(Integer, primary_key=True)
relation_id = Column(Integer, ForeignKey('ModelRelation.row_id'))
relation = relationship('ModelRelation')
@hybrid_property
def value(self):
return self.relation.name
@value.expression
def value(cls):
return select([ModelRelation.name]).where(ModelRelation.row_id==cls.relation_id)
@hybrid_property
def value_scalar(self):
return self.relation.name
@value_scalar.expression
def value_scalar(cls):
return select([ModelRelation.name]).where(ModelRelation.row_id==cls.relation_id).as_scalar()
Base.metadata.create_all()
if __name__ == '__main__':
session = Session()
script1 = Model(relation=ModelRelation(name='value1'))
session.add(script1)
script2 = Model(relation=ModelRelation(name='value2'))
session.add(script2)
session.commit()
print([i.value for i in session.query(Model).all()])
print(session.query(Model.value).all())
print(session.query(Model).filter(Model.value=='value1').all())
print()
print([i.value_scalar for i in session.query(Model).all()])
print(session.query(Model.value_scalar).all())
print(session.query(Model).filter(Model.value_scalar=='value1').all())
session.close()
输出是:
[u'value1', u'value2']
[(u'value1',), (u'value2',)]
[]
[u'value1', u'value2']
[(u'value1',)]
[<__main__.Model object at 0x041D5C90>]
【问题讨论】:
-
我认为每个
@hybrid_property不应该有多个表达式,并且您不直接调用表达式方法,仍然查询@hybrid_property属性。例如。删除value_scalar()方法,这个session.query(Model.value).all()返回[('value1',), ('value2',)],session.query(Model).filter(Model.value == "value1").all()返回[<__main__.Model object at 0x0000022578989E08>]。没有写答案,因为不确定我是否正确理解了您的问题,但我之前没有看到单个混合属性具有多种表达方法的模式。 -
这是
.filter(Model.value_not_scalar == "value1")查询生成的sql:SELECT "Model".row_id AS "Model_row_id", "Model".name AS "Model_name" FROM "Model" WHERE 0 = 1。请注意末尾的WHERE 0 = 1部分,因此结果为空。 -
我通常不会对一个属性执行两个表达式,我只是发现它给出了相同的结果。当我清理我的代码时,我并没有意识到删除关系将允许
hybrid_property自动生成表达式,但我的实际问题是关系不会发生这种情况。虽然再次添加了关系(我将更新问题中的代码),但如果不专门定义表达式,它将无法工作。
标签: python sqlalchemy