deo*_*ian 5 python postgresql orm many-to-many sqlalchemy
我有一些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])
Run Code Online (Sandbox Code Playgroud)
通过此设置,我可以使用新标签创建任务。它在tags表中创建标签行,然后在表中创建与新任务的关联tasktags。
t = Task(task_id = uuid4(), tags=['foo', 'bar']) #this works
Run Code Online (Sandbox Code Playgroud)
当我尝试使用tags表中已经存在的标签创建任务时,就会出现问题。
t2 = Task(task_oid = uuid4(), tags=['foo', 'baz']) #this will give an integrity error
Run Code Online (Sandbox Code Playgroud)
似乎SQLAlchemy 总是尝试将标签插入标签表中,无论它是否已经存在。我真的希望它仅在标记已存在的情况下才创建关联。在很多情况下,这似乎很正常,但是我在文档中找不到任何地方显示了我可能做错了什么。
有没有办法得到我想要的行为?
对于背景,我使用带有sypsgg2驱动程序的Postgresql 9.1 DB和SQLAlchemy 0.7.9(Python 2.7.3)
我正在考虑的最后一件事:从技术上讲,标签是主键,没有别的,我只能使用task_id-> tag表而没有标签表。但我希望能够在必要时将元数据附加到标签本身。
对于“仅唯一标签”配方,我通常使用唯一对象配方或其某些变体: http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject。
这自然需要对特定行进行 SELECT 操作,以便首先判断该行是否存在。“upsert”技术使用特定于数据库的命令根据数据库端的确定来插入或更新行,目前 ORM 不直接支持。无论如何,你使用的是 Postgresql,它实际上不支持任何本机“upsert”功能,除了一个使用公用表表达式的非常尴尬的系统。