我有一个sqlalchemy(实际上是Flask-sqlalchemy因此所有的db。*),我希望能够通过他们与之相关的“投票”的平均投票价值来排序我的“事物”。投票的值为0到100。
遇到sqlalchemy想将average_vote_value @attribute翻译成sql并且失败的问题我发现我应该使用hybrids:
然而,我无法弄清楚在这种情况下如何做到这一点。有人可以帮忙吗?
class Thing(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80))
votes = db.relationship('Vote', backref='thing', lazy='dynamic')
@hybrid_property
def average_vote_value(self):
'''average of vote.values'''
values = [v.value for v in self.votes]
try:
return sum(scores) / len(values)
except ZeroDivisionError:
return 50 # the default value
average_vote_value.expression
def average_vote_value(cls):
pass ### help ###
class Vote(db.Model):
id = db.Column(db.Integer, primary_key=True)
thing_id = db.Column(db.Integer, db.ForeignKey('thing.id'))
value = db.Column(db.Float, default=50.0)
答案 0 :(得分:16)
在一天结束时,您需要考虑如何将您想要的结果作为SQL查询。你不能仅仅从“混合,python,属性”等方面来考虑它。虽然我们将使用这些技术来获得结果,但这是SQL工作方式引领我们的方式。所以让我们使用Postgresql,它内置AVG功能,大多数数据库都有。我们将需要从Thing加入投票,因为你想要考虑Thing没有投票的情况,一个LEFT OUTER JOIN。混合表达式只是您想要的SQL表达式的语法帮助,但在一天结束时,您仍需要拼出SQL所需的JOIN:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.ext.declarative import declarative_base
Base= declarative_base()
class Thing(Base):
__tablename__ = 'thing'
id = Column(Integer, primary_key=True)
name = Column(String(80))
votes = relationship('Vote', backref='thing', lazy='dynamic')
@hybrid_property
def average_vote_value(self):
'''average of vote.values'''
values = [v.value for v in self.votes]
try:
return sum(values) / len(values)
except ZeroDivisionError:
return 50 # the default value
@average_vote_value.expression
def average_vote_value(cls):
return func.coalesce(func.avg(Vote.value), 50)
class Vote(Base):
__tablename__ = 'vote'
id = Column(Integer, primary_key=True)
thing_id = Column(Integer, ForeignKey('thing.id'))
value = Column(Float, default=50.0)
e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
Base.metadata.drop_all(e)
Base.metadata.create_all(e)
s = Session(e)
s.add_all([
Thing(name="thing1", votes=[
Vote(value=5),
Vote(value=7),
Vote(value=7),
Vote(value=8),
Vote(value=8),
Vote(value=12),
Vote(value=2),
Vote(value=15),
Vote(value=10),
]),
Thing(name="thing2", votes=[
Vote(value=18),
Vote(value=16),
Vote(value=27),
Vote(value=6),
Vote(value=10),
]),
Thing(name="thing3", votes=[])
]
)
s.commit()
print s.query(Thing.name, Thing.average_vote_value).\
outerjoin(Thing.votes).\
group_by(Thing.name).all()
输出(减去回声):
[(u'thing3', 50.0), (u'thing1', 8.22222222222222), (u'thing2', 15.4)]