8

私はいくつかの ORM マップ テーブルを持っています。

class Tag(Base):
    __tablename__ = 'tags'

    tag_name = Column(String, primary_key=True)

task2tag_assoc = Table('tasktags', Base.metadata,
    Column('task_id', UUID, ForeignKey('tasks.task_id', ondelete='cascade'), 
           primary_key=True),
    Column('tag_name', String, ForeignKey('tags.tag_name', ondelete='cascade'),
           primary_key=True)
    )

class Task(Base):
    __tablename__ = 'tasks'

    task_id = Column(UUID, primary_key=True)
    _tags = relationship('Tag', secondary=task2tag_assoc, backref='tasks',
            collection_class=set)
    tags = association_proxy('_tags', 'tag_name')

    def __init__(self, task_id, tags):
        self.task_id = task_id
        self.tags = set([tags])

このセットアップでは、新しいタグを使用して問題なくタスクを作成できます。テーブルにタグ行をtags作成し、新しいタスクへの関連付けをテーブルに作成しtasktagsます。

t = Task(task_id = uuid4(), tags=['foo', 'bar']) #this works

テーブルに既に存在するタグを使用してタスクを作成しようとすると、問題が発生しtagsます。

t2 = Task(task_oid = uuid4(), tags=['foo', 'baz']) #this will give an integrity error

SQLAlchemyは、既に存在するかどうかにかかわらず、常にタグ テーブルにタグを挿入しようとするようです。タグが既に存在する場合にのみ関連付けを作成したいと思います。これは、多対多の状況ではごく普通のことのように思えますが、ドキュメントのどこにも、私が間違っている可能性があることを示している箇所が見つかりません。

私が望む動作を取得する方法はありますか?

背景として、私はpsycopg2ドライバーとSQLAlchemy 0.7.9(Python 2.7.3)を備えたpostgresql 9.1 DBを使用しています

私が最後の手段として考えていること: タグは技術的には主キーであり、他には何もありません。私は task_id->tag テーブルだけでタグテーブルなしで逃げることができました。しかし、必要に応じて、メタデータをタグ自体に添付できるようにしたいと考えています。

4

2 に答える 2

4

「一意のタグのみ」のレシピでは、通常、一意のオブジェクト レシピ、またはその変形を使用します: http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject

これには、最初に存在するかどうかを確認するために、特定の行に対する SELECT が当然必要です。データベース固有のコマンドを使用して、データベース側の決定に基づいて行を INSERT または UPDATE する「アップサート」手法は、現在 ORM で直接サポートされていません。とにかく、一般的なテーブル式を使用する非常に厄介なシステムを除いて、実際にはネイティブの「アップサート」機能をサポートしていない Postgresql を使用しています。

于 2012-10-31T02:57:31.830 に答える
0

この t2._tags = [] のような関連リンクを削除してみてください

t2 = Task(task_oid = uuid4())
t2._tags = []
tags = ['foo', 'baz']
for tag in tags:
    t2._tags.append(Tag(tag))
于 2012-10-31T07:28:34.590 に答える