我已经四处寻找类似主题的帮助,但无法找到解决SQLAlchemy / Flask-SQLAlchemy问题的正确解决方案。
情况如下:我有3个表格来处理抽奖券数据。表格如下:A'抽奖活动'表:
class RaffleModel(db.Model):
__tablename__ = 'raffles'
id = db.Column(db.Integer, primary_key=True)
# relationship to users
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
user = db.relationship("UserModel", backref="raffles")
# relationship to ticket_md
ticket_md_id = db.Column(db.Integer, db.ForeignKey('ticket_mds.id'))
ticket_md = db.relationship("TicketMetaDataModel", backref="raffles")
def __init__(self, user, ticket_md):
self.user = user
self.ticket_md = ticket_md
使用以下示例数据:
id user_id ticket_md_id
1 1 1
2 2 1
3 3 1
4 1 2
5 2 2
A'用户'表:
class UserModel(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(25))
last_name = db.Column(db.String(25))
won = db.Column(db.Boolean, default=False, nullable=False)
# has backref via user.raffles
def __init__(self, first_name, last_name, won):
self.first_name = first_name
self.last_name = last_name
self.won = won
使用以下示例数据:
id first_name last_name won
1 Rob Stark False
2 Stan Clark False
3 Tom Dark False
最后一个' ticket_mds'表:
class TicketMetaDataModel(db.Model):
__tablename__ = 'ticket_mds'
id = db.Column(db.Integer, primary_key=True)
raffle_type = db.Column(db.String(20))
description = db.Column(db.String(200))
modifier = db.Column(db.Integer)
# has backref via ticket_md.raffles
def __init__(self, raffle_type, description, modifier):
self.raffle_type = raffle_type
self.description = description
self.modifier = modifier
使用以下示例数据:
id raffle_type description modifier
1 type_1 blah blah 21
2 type_2 blah blah 5
我的问题在于,我似乎无法找出一个查询来获取用户从抽奖表中分组的票点总和(基于TicketMetaDataModel.modifier属性)返回结果如下:
first_name,last_name,total_points e.g:
Rob Stark 26
Stan Clark 26
Tom Dark 21
我尝试了以下内容(但未能从那里得到更多):
query = db.session.query(RaffleModel.id, UserModel.first_name, UserModel.last_name, TicketMetaDataModel.modifier)
query = query.join(UserModel).join(TicketMetaDataModel)
results = query.all()
results equals:
[(1, 'Rob', 'Stark', 21), (2, 'Stan', 'Clark', 21), (3, 'Tom', 'Dark', 21),(4, 'Rob', 'Stark', 5), (5, 'Stan', 'Clark', 5)]
我知道要消化很多,但是非常感谢任何帮助
答案 0 :(得分:2)
如果我的问题是对的。您正尝试按已经通过连接获得的值进行分组。
from sqlalchemy import func
query = db.session.query(UserModel.first_name, UserModel.last_name, func.sum(TicketMetaDataModel.modifier))
query = query.join(RaffleModel,RaffleModel.user_id==UserModel.id).join(RaffleModel.ticket_md_id==TicketMetaDataModel.id)
.group_by(UserModel.first_name, UserModel.last_name)
它应该给你所需的结果
答案 1 :(得分:1)
这让我很感兴趣,我做了一个自成一体的例子
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, ForeignKey, String, Boolean
from sqlalchemy.orm import relationship, sessionmaker
from pprint import pformat as pf
Base = declarative_base()
class ReprMixin(object):
"""A mixin to implement a generic __repr__ method"""
def as_dict(self):
"""return instance as a dictionary"""
return {c.name: getattr(self, c.name) for c in self.__table__.columns}
def __repr__(self):
return '<%s(%s)>' % (self.__class__.__name__, ', '.join([f'{c.name} = {getattr(self, c.name)}' for c in self.__table__.columns]))
class RaffleModel(ReprMixin, Base):
__tablename__ = 'raffles'
id = Column(Integer, primary_key=True)
# relationship to users
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship("UserModel", backref="raffles")
# relationship to ticket_md
ticket_md_id = Column(Integer, ForeignKey('ticket_mds.id'))
ticket_md = relationship("TicketMetaDataModel", backref="raffles")
def __init__(self, user, ticket_md):
self.user = user
self.ticket_md = ticket_md
@classmethod
def insert_defaults(cls, session):
for user_id, ticket_id in zip([1,2,3,1,2],[1,1,1,2,2]):
user = session.query(UserModel).filter_by(id=user_id).scalar()
ticket = session.query(TicketMetaDataModel).filter_by(id=ticket_id).scalar()
session.add(cls(user, ticket))
session.commit()
class UserModel(ReprMixin, Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
first_name = Column(String(25))
last_name = Column(String(25))
won = Column(Boolean, default=False, nullable=False)
# has backref via user.raffles
def __init__(self, first_name, last_name, won):
self.first_name = first_name
self.last_name = last_name
self.won = won
@classmethod
def insert_defaults(cls, session):
for first_name, last_name, won in zip("Rob Stan Tom".split(),"Stark Clark Dark".split(), [False]*3):
session.add(cls(first_name, last_name, won))
session.commit()
class TicketMetaDataModel(ReprMixin, Base):
__tablename__ = 'ticket_mds'
id = Column(Integer, primary_key=True)
raffle_type = Column(String(20))
description = Column(String(200))
modifier = Column(Integer)
# has backref via ticket_md.raffles
def __init__(self, raffle_type, description, modifier):
self.raffle_type = raffle_type
self.description = description
self.modifier = modifier
@classmethod
def insert_defaults(cls, session):
for raffle_type, description, modifier in zip("type1 type2".split(), "desc1 desc2".split(), [21,5]):
session.add(cls(raffle_type, description, modifier))
session.commit()
if __name__ == '__main__':
from pprint import pprint as pp
engine = create_engine('sqlite://')
Session = sessionmaker()
sess = Session(bind=engine)
Base.metadata.create_all(bind=engine)
TicketMetaDataModel.insert_defaults(sess)
UserModel.insert_defaults(sess)
RaffleModel.insert_defaults(sess)
print('************************')
pp(sess.query(UserModel).all())
print('************************')
pp(sess.query(RaffleModel).all())
print('************************')
pp(sess.query(TicketMetaDataModel).all())
from sqlalchemy import func
query = sess.query(UserModel.first_name, UserModel.last_name, func.sum(TicketMetaDataModel.modifier))
query2 = query.join(RaffleModel.user)\
.join(RaffleModel.ticket_md)\
.group_by(UserModel.first_name, UserModel.last_name)
print('************************')
print(query)
print(query.all())
print('************************')
print(query2.all())
print(query2)
Base.metadata.drop_all(engine)
运行它返回
************************
[<UserModel(id = 1, first_name = Rob, last_name = Stark, won = False)>,
<UserModel(id = 2, first_name = Stan, last_name = Clark, won = False)>,
<UserModel(id = 3, first_name = Tom, last_name = Dark, won = False)>]
************************
[<RaffleModel(id = 1, user_id = 1, ticket_md_id = 1)>,
<RaffleModel(id = 2, user_id = 2, ticket_md_id = 1)>,
<RaffleModel(id = 3, user_id = 3, ticket_md_id = 1)>,
<RaffleModel(id = 4, user_id = 1, ticket_md_id = 2)>,
<RaffleModel(id = 5, user_id = 2, ticket_md_id = 2)>]
************************
[<TicketMetaDataModel(id = 1, raffle_type = type1, description = desc1, modifier = 21)>,
<TicketMetaDataModel(id = 2, raffle_type = type2, description = desc2, modifier = 5)>]
************************
SELECT users.first_name AS users_first_name, users.last_name AS users_last_name, sum(ticket_mds.modifier) AS sum_1
FROM users, ticket_mds
[('Tom', 'Dark', 78)]
************************
[('Rob', 'Stark', 26), ('Stan', 'Clark', 26), ('Tom', 'Dark', 21)]
SELECT users.first_name AS users_first_name, users.last_name AS users_last_name, sum(ticket_mds.modifier) AS sum_1
FROM raffles JOIN users ON users.id = raffles.user_id JOIN ticket_mds ON ticket_mds.id = raffles.ticket_md_id GROUP BY users.first_name, users.last_name
如果RaffleModel
是UserModel
和TicketMetadataModel