我在SQLAlchemy中有一个关联对象,它为另外两个对象提供了一些额外的信息(实际上是一个字段)。
第一个对象是Photo
模型,第二个对象是PhotoSet
,关联对象叫PhotoInSet
,它保存position
属性,告诉我们什么position是当前Photo
中的PhotoSet
。
class Photo(Base):
__tablename__ = 'photos'
id = Column(Integer, primary_key=True)
filename = Column(String(128), index=True)
title = Column(String(256))
description = Column(Text)
pub_date = Column(SADateTime)
class PhotoInSet(Base):
__tablename__ = 'set_order'
photo_id = Column(Integer, ForeignKey('photos.id'), primary_key=True)
photoset_id = Column(Integer, ForeignKey('photo_set.id'), primary_key=True)
position = Column(Integer)
photo = relationship('Photo', backref='sets')
def __repr__(self):
return '<PhotoInSet %r>' % self.position
class PhotoSet(Base):
__tablename__ = 'photo_set'
id = Column(Integer, primary_key=True)
name = Column(String(256))
description = Column(Text)
timestamp = Column(SADateTime)
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship('User', backref=backref('sets', lazy='dynamic'))
photo_id = Column(Integer, ForeignKey('photos.id'))
photos = relationship('PhotoInSet', backref=backref('set', lazy='select'))
我创建一个新的PhotoSet
保存position
并创建关系是没有问题的,这是(大致)这样做的:
# Create the Set
new_set = PhotoSet(name, user)
# Add the photos with positions applied in the order they came
new_set.photos.extend(
[
PhotoInSet(position=pos, photo=photo)
for pos, photo in
enumerate(photo_selection)
]
)
但是我在尝试找出订单更改时如何更新position
时遇到了很多麻烦。
如果我有3个Photo
个带有id的对象:1,2和3,以及位置1,2和3,则在创建后会如下所示:
>>> _set = PhotoSet.get(1)
>>> _set.photos
[<PhotoInSet 1>, <PhotoInSet 2>, <PhotoInSet 3>]
如果订单发生变化,(让我们反转此示例的顺序),SQLAlchemy是否可以帮助我更新position
值?到目前为止,我对我能提出的任何方法都不满意。
最简洁的方法是什么?
答案 0 :(得分:3)
查看Ordering List扩展程序:
orderinglist是可变有序关系的帮助者。它会 在关系()上执行的拦截列表操作 - 托管 收集并自动同步列表位置的更改 目标标量属性。
我相信您可以将架构更改为:
from sqlalchemy.ext.orderinglist import ordering_list
# Photo and PhotoInSet stay the same...
class PhotoSet(Base):
__tablename__ = 'photo_set'
id = Column(Integer, primary_key=True)
name = Column(String(256))
description = Column(Text)
photo_id = Column(Integer, ForeignKey('photos.id'))
photos = relationship('PhotoInSet',
order_by="PhotoInSet.position",
collection_class=ordering_list('position'),
backref=backref('set', lazy='select'))
# Sample usage...
session = Session()
# Create two photos, add them to the set...
p_set = PhotoSet(name=u'TestSet')
p = Photo(title=u'Test')
p2 = Photo(title='uTest2')
p_set.photos.append(PhotoInSet(photo=p))
p_set.photos.append(PhotoInSet(photo=p2))
session.add(p_set)
session.commit()
print 'Original list of titles...'
print [x.photo.title for x in p_set.photos]
print ''
# Change the order...
p_set.photos.reverse()
# Any time you change the order of the list in a way that the existing
# items are in a different place, you need to call "reorder". It will not
# automatically try change the position value for you unless you are appending
# an object with a null position value.
p_set.photos.reorder()
session.commit()
p_set = session.query(PhotoSet).first()
print 'List after reordering...'
print [x.photo.title for x in p_set.photos]
此脚本的结果......
Original list of titles...
[u'Test', u'uTest2']
List after reordering...
[u'uTest2', u'Test']
在你的评论中,你说......
所以这意味着如果我为_set.photos分配一个新列表,我可以免费获得定位吗?
我怀疑是这种情况。