2012-06-02 5 views
4

나는 sqlalchemy를 가지고있다. (실제로 Flask-sqlalchemy 따라서 모든 db. *) 나는 그들과 관련이있는 'Votes'의 평균 투표로 내 'Things'를 분류 할 수 있기를 바란다. .Sqlalchemy 하이브리드

하지만 난 그냥 수 : 투표 수는 SQLAlchemy의이 SQL에 average_vote_value @attribute 번역을 좋아하고 내가 아마 hybrids을 사용해야 찾을 실패 할 것이라는 점을 문제로 실행하는 데 100

-0의 값이 이 경우에 어떻게 이루어 졌는지를 알아 내야합니다. 아무도 도와 줄 수 있습니까?

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) 

답변

15

하루가 끝나면 SQL 쿼리로 원하는 결과를 얻는 방법을 고려해야합니다. "하이브리드, 파이썬, 속성"등의 용어로만 생각할 수는 없습니다. 이러한 기술을 사용하여 결과를 얻으려는 동안 SQL이 우리를 이끄는 방식입니다. 그래서 Postgresql을 사용합시다. 그리고 대부분의 데이터베이스에있는 AVG 함수로 만들어졌습니다. 우리는 씽에서 투표로 가야하고, 투표에 투표가없는 경우를 고려해야하므로 왼쪽 외부 조인을해야합니다. 하이브리드 표현은 원하는 SQL 식에 대한 단지 구문 도우미이지만, 하루의 끝에서 당신은 여전히 ​​SQL이 필요로하는 가입 철자해야

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:[email protected]/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)]