我有User(db.Model)和Photo(db.Model)以及它们之间的一对多关系,因此用户有很多照片。
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
photos = db.relationship('Photo', backref='user', lazy='dynamic')
def to_json(self):
json = {
'id': self.id,
'photos': [photo.to_json() for photo in self.photos] if self.photos else None,
'name': self.name
}
return json
class Photo(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
name = db.Column(db.String(1024), nullable=False)
def to_json(self):
json = {
'id': self.id,
'user_id': self.user_id,
'name': self.name
}
return json
我的目标是使用单个查询选择包含所有照片的所有用户,并使用原生查询完成:
from sqlalchemy import text
statement = text('SELECT u.*, p.* FROM user u LEFT JOIN photo p ON u.id=p.user_id')
user_photo_query = db.session.query(User, Photo).from_statement(statement)
user_photo_tuples = user_photo_query.all()
users_dict = {}
db.session.expunge_all()
db.session.close()
for u, p in user_photo_tuples:
if not users_dict.get(u.id, None):
u.photos = list()
users_dict.update({u.id: u})
users_dict.get(u.id).photos.append(p)
users = users_dict.values()
return jsonify({'users': [user.to_json() for user in users]})
在此查询的结果中,有元组列表(User_240298428,Photo_20394823)。该列表的每个记录中的照片都不同。对于列表的某些记录,用户是相同的。因为我不希望用户和照片对象再次绑定到会话,我做了:
db.session.expunge_all()
db.session.close()
所以我遍历列表并尝试在相应的user.photos列表中添加所有照片。
users_dict.get(u.id).photos.append(p)
我收到错误:
父实例不是 绑定到会话;延迟加载属性'user'的操作不能 继续
这是因为用户对象与照片对象的关系:
photos = db.relationship('Photo', backref='user', lazy='dynamic')
我想要的是将user.photos用作常规列表,而不是SQLAlchemy关系。我想将照片添加到用户列表中,而不是以某种方式连接到sqlalchemy。希望很清楚
答案 0 :(得分:2)
有些东西让我觉得你没有正确使用你的sqlalchemy模型。为什么,而不是从会话中分离并使用您的关系(使用相同用户的多个元组?)进行奇怪的事情,您是否可以通过使用SQLalchemy的机制来为每个用户创建照片列表?
如果你有用户和照片之间的关系,你可以:
将关系加载策略更改为默认值(完全删除lazy属性或将其设置为'select'),然后为用户查询数据库:
users = db.session.query(User).all()
...并以db对象列表的形式访问用户的照片。
user.photos # photos is a list of all user's photos
lazy='dynamic'
您可以通过相同的方式覆盖所有用户,但现在照片也是一个查询(请参阅:dynamic relationships):
启用大型集合管理的关键功能是所谓的“动态”关系。这是一种可选的relationship()形式,它在访问时返回一个Query对象来代替集合
...与每个查询一样,您可以使用其API(filter()
,first()
或all()
来获取所有照片。