2017-05-21 14 views
1

要約:SQLAlchemyにアドレスのリストを整列させたい。 コミットすると私のリストの順番が変わります。 なぜこれが起こり、どのように変更できますか?SQLAlchemy InstrumentedListの順序が永続的でないのはなぜですか?

ロング説明:

  1. 私はUserオブジェクトに添付アドレスのリストを開始します。
  2. 次に、「アドレス」リストの最初の要素を 新しいアドレスに置き換えます。
  3. 次に、私はアドレスのリストを印刷します...今のところ、注文は私が期待するものです。
  4. 最後にコミットします。コミット後、私はクエリを実行しますが、私の アドレスリストの順序が変更されました。

これは私が理解していない一般的なデータベースの一般的なことですか?または、SQLAlchemy InstrumentedListは実際のリストのように動作しませんか?私は関係の中で要素の順序を変えることができると思ったが、どのように見えるのか分からない。


from sqlalchemy import Column, Integer, String 
from sqlalchemy import create_engine 
from sqlalchemy import ForeignKey 
from sqlalchemy.orm import relationship 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker 

Base = declarative_base() 
Session = sessionmaker() 

class User(Base): 
    __tablename__ = 'users' 
    id = Column(Integer, primary_key=True) 
    name = Column(String(50)) 
    fullname = Column(String(50)) 
    password = Column(String(12)) 

    addresses = relationship("Address", back_populates="user") 

    def __repr__(self): 
     return "<User(name='%s', fullname='%s', password='%s')>" % (
           self.name, self.fullname, self.password) 

class Address(Base): 
    __tablename__ = 'addresses' 
    id = Column(Integer, primary_key=True) 
    email_address = Column(String, nullable=False) 
    user_id = Column(Integer, ForeignKey('users.id')) 

    user = relationship("User", back_populates="addresses") 

    def __repr__(self): 
     return "<Address(email_address='%s')>" % self.email_address 


if __name__ == "__main__": 
    engine = create_engine('sqlite:///:memory:', echo=False) 
    Session.configure(bind=engine) 
    Base.metadata.create_all(engine) 
    session = Session() 

    user = User(name='ed', fullname='Ed Jones', password='edspassword') 
    user.addresses = [Address(email_address='[email protected]'), Address(email_address='[email protected]')] 
    session.add(user) 
    session.commit() 

    user = session.query(User).filter_by(name='ed').first() 

    print("Current order of addresses list at start.") 
    print(user.addresses) 
    print() 

    new_primary_address = Address(email_address='[email protected]') 
    user.addresses[0] = new_primary_address 

    print("Current order of addresses list before commit.") 
    print("But after chaning addresses[0].") 
    print(user.addresses) 
    print() 

    session.commit() 

    user = session.query(User).filter_by(name='ed').first() 

    print("Current order of addresses list after commit.") 
    print(user.addresses) 
    print() 

    print("Why is the order of the InstrumentedList not persistent?") 
    print("Isn't persistent order what makes a list a list?") 
+0

最初のアイテムを置き換えるのではなく、削除して明示的に新しいアイテムをインデックスゼロに挿入してみましたか? –

+0

はい。同じ問題。マークされた答えは理由を説明します。クエリはデフォルトでun-orderedで発行されます。リストの順序は、リストの順序を追跡する特別な列がなければ維持できません。 –

答えて

2

これは、一般的には、 "データベース化" です。 InstrumentedListは、ORM計測器のPython側が追加された実際のlistのように機能しますが、commitの場合は、ORM管理属性のすべてのデータベースがロードされた状態を期限切れにするというデフォルトの動作であり、次回のアクセス時にリストを更新する必要があります。これは、リスト内容を取り出すために、

2017-05-21 13:32:31,124 INFO sqlalchemy.engine.base.Engine SELECT addresses.id AS addresses_id, addresses.email_address AS addresses_email_address, addresses.user_id AS addresses_user_id 
FROM addresses 
WHERE ? = addresses.user_id 

などのSELECTが発行されることを意味します。 SQL the order of a SELECT is unspecifiedでは、明示的に選択されていない場合、以前と同じ順序で項目を取得する場合としない場合があります。またしても、ORM操作

user.addresses[0] = new_primary_address 

がNULLに古いアドレスタプルのuser_idを設定し、テーブルに新しいものを挿入UPDATEに変換するので、あなたはあなたが思った順序を得ないだろうことに注意してください行は挿入順に戻されました。

住所の順序が重要な場合は、注文を選択する必要があります。フェッチ

class User(Base): 
    ... 
    addresses = relationship("Address", back_populates="user", 
          order_by="Address.email_address") 

は、電子メールアドレスでアドレスを注文します:relationshiporder_byパラメータを使用します。また、SQLAlchemyは、変更可能な順序関係のヘルパーコレクションクラスを提供しています()。

アドレスの順序がユーザーの主なアドレスであることを示しているようです。このために別のフラグ列を使用すると効果的です。

+0

それは道理にかなっています。私は主に独学で学習していますが、私が間違っている場所を見つけ出すのが難しいと感じています。私の質問は、私が取り組んでいる問題のより単純なユースケースでした。http://docs.sqlalchemy.org/en/latest/orm/extensions/orderinglist.htmlトリックをするだろう。説明のためにもう一度おねがいします:) –

+2

'orderinglist'で良い見つける、前にそれを知らなかった。あなたが気にしないなら、私は答えにそれを含めるつもりです。 –

+0

実際の使用例(実際に長い読書を気にしない場合)については、https://github.com/elthran/RPG-Game/tree/37451e67c531b2357d6a92552e101e4132762c37を参照してください。 –

関連する問題