2011-07-12 17 views
0

私はPython 2.6.6とSQLAlchemy 0.6.6を使用してデータベース内の1対多の関係を処理していますが、類似したデータがすでに存在する場合にSQLAlchemyが新しい子レコードを追加するのを防ぐ方法は不明です。子どもがSQLAlchemyの1対多リレーションシップで再作成されないようにするにはどうすればよいですか?

データベースコード:

from sqlalchemy import * 
from sqlalchemy.orm import backref, relationship, sessionmaker, create_session 
from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base() 

# Parent table, no foreign key. 
class Author(Base): 
    __tablename__ = 'authors' 

    id = Column(Integer, primary_key=True) 
    username = Column(String) 
    author_metadata = relationship('AuthorMetadata', backref='author') 

# Child table, many records with same author_id. 
class AuthorMetadata(Base): 
    __tablename__ = 'author_metadata' 

    id = Column(Integer, primary_key=True) 
    author_id = Column(Integer, ForeignKey('authors.id')) 
    metakey = Column(String) 
    metavalue = Column(Text) 

スクリプト例:

dev=# select id from authors where username = 'Godfrey'; 
    id 
------ 
5025 
(1 row) 

dev=# select id, author_id, metakey, metavalue from author_metadata order by id desc limit 2; 
    id | author_id | metakey | metavalue 
-------+-----------+----------+----------- 
85090 |  5025 | posts | 5 
85089 |  5025 | location | New York 
(2 rows) 

if __name__ == '__main__': 
    engine = create_engine('database_details', pool_recycle=90) 
    session = create_session(bind=engine) 

    author = session.query(Author).filter_by(username='Godfrey').first() 
    if not author: 
     author = Author() 
    author.username = 'Godfrey' 
    author.author_metadata = [ 
     AuthorMetadata(metakey='location', metavalue='New York'), 
     AuthorMetadata(metakey='posts', metavalue='5')] 
    session.add(author) 
    session.flush() 

私は例のスクリプトを実行する最初の時間は、以下のデータベース(予想通り)に表示されます。

サンプルスクリプトをもう一度実行すると、既存のメタデータレコードの作成者IDがnullに設定して、新しいレコードが挿入されています:

dev=# select id, author_id, metakey, metavalue from author_metadata order by id desc limit 4; 
    id | author_id | metakey | metavalue 
-------+-----------+----------+----------- 
85092 |  5025 | posts | 5 
85091 |  5025 | location | New York 
85090 |   | posts | 5 
85089 |   | location | New York 
(4 rows) 

私は、これは驚くべき見つけることはありませんが、それが唯一の削除/修正/挿入する必要があることをSQLAlchemyのに通信できるようにする良い方法がある場合は疑問に思って新しいメタデータのリストが既存のリストと異なる場合は、作成者のメタデータ行。

答えて

1

リストの内容を明示的にチェックし、新しいAuthorMetadataオブジェクトが存在しない場合は、コレクション全体を削除して新しいオブジェクトで再作成するのではなく、そのオブジェクトのみを追加できます。それは、少なくとも以前に作成されたレコードを破棄するのを避けるでしょう。

あなたのユースケースはattribute_mapped_collectionassociation_proxyとよく一致しているので、そのうちの1つと一緒に行きたいと思うかもしれません。

+0

+1 to column/attribute_mapped_collection。 –

+0

jdとマークをありがとう!マップされたコレクションとアソシエーションのプロキシーに関する提案をhttp://stackoverflow.com/questions/1400537/dictionary-of-tags-in-declarative-sqlalchemyとともに使用して、私が後にしたことを思いついた。 – christopherwright

関連する問題