2013-10-19 72 views
0

我在SQLAlchemy中有一個關聯對象,它有2個其他對象的一些額外信息(實際上是一個字段)。更新SQLAlchemy中的關聯對象中的字段

的第一個對象是Photo模型,第二個目的是PhotoSet和關聯對象被稱爲PhotoInSet其持有position屬性,它告訴我們在什麼位置是在當前PhotoSetPhoto

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對象與IDS:1,2,3,和位1,2和3分別是這樣的創建後:

>>> _set = PhotoSet.get(1) 
>>> _set.photos 
[<PhotoInSet 1>, <PhotoInSet 2>, <PhotoInSet 3>] 

如果訂單改變,(讓反例這個例子的順序),是否有SQLAlchemy可以幫助我更新position值?到目前爲止,我對我能想出的任何方法都不滿意。

什麼是最簡潔的方式來做到這一點?

回答

2

看看在Ordering List擴展:

orderinglist is a helper for mutable ordered relationships. It will intercept list operations performed on a relationship()-managed collection and automatically synchronize changes in list position onto a target scalar attribute.

我相信你可以改變你的架構看起來像:

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'] 

在你的評論中,你說...

So this would mean that if I assign a new list to _set.photos I get the positioning for free?

我懷疑是這樣。

+0

所以這意味着如果我給'_set.photos'分配一個新的列表,我可以免費獲得定位? – alfredodeza

+0

Mnn似乎有什麼我失蹤。我在'set'上得到'KeyError'。如果我刪除了'backref',它會失敗並出現'AttributeError:'Photo'對象沒有屬性'位置' – alfredodeza

+0

設置上的KeyError在原始模式中也是一個問題,我相信。第二個錯誤可能是因爲您將'Photo'對象附加到photo_set.photos而不是'PhotoInSet'對象。 –

相關問題