我有一个有点复杂的插入操作,它可以归结为:
我能以某种方式比用SQLALchemy语法编写那些更容易吗?
答案 0 :(得分:2)
简答:在creator
的定义中使用自定义association_proxy
:
def _tag_find_or_create(tag_name):
tag = Tag.query.filter_by(tag_name=tag_name).first()
return tag or Tag(tag_name=tag_name)
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True)
book_name = Column(String)
# relationship
_tags = relationship('Tag', secondary='book_tag')
tags = association_proxy('_tags', 'tag_name', creator=_tag_find_or_create)
长答案:以下代码是一个独立的工作示例。关于实施的几句话:
Association Proxy
来简化many-to-many
关系。给整个页面一个很好的阅读。creator
函数,该函数将首先查询数据库/会话以检查Tag
,如果找不到则创建一个。代码:
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy import UniqueConstraint, ForeignKey
from sqlalchemy.orm import relationship, scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
# Configure test data SA
engine = create_engine('sqlite:///:memory:', echo=True)
session = scoped_session(sessionmaker(bind=engine))
Base = declarative_base(engine)
Base.query = session.query_property()
def _tag_find_or_create(tag_name):
tag = Tag.query.filter_by(tag_name=tag_name).first()
return tag or Tag(tag_name=tag_name)
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True)
book_name = Column(String)
# relationship
_tags = relationship('Tag', secondary='book_tag')
tags = association_proxy('_tags', 'tag_name', creator=_tag_find_or_create)
class BookTag(Base):
__tablename__ = 'book_tag'
__tableargs__ = (UniqueConstraint('book_id', 'tag_id', name='book_tag_uc'),)
id = Column(Integer, primary_key=True)
book_id = Column(Integer, ForeignKey('book.id'))
tag_id = Column(Integer, ForeignKey('tag.id'))
class Tag(Base):
__tablename__ = 'tag'
id = Column(Integer, primary_key=True)
tag_name = Column(String, unique=True)
# CREATE SCHEMA
Base.metadata.create_all()
def _insert_test_data():
book = Book(book_name="book-1")
book.tags.append("fiction")
book.tags.append("history")
session.add(book)
session.commit()
assert 1 == len(Book.query.all())
assert 2 == len(Tag.query.all())
book2 = Book(book_name="book-2")
book2.tags.append("history")
book2.tags.append("crime")
session.add(book2)
session.commit()
assert 2 == len(Book.query.all())
assert 3 == len(Tag.query.all())
def _add_new_book(book_name, tags):
book = Book.query.filter(Book.book_name == book_name).first()
assert not(book), "Book with name '{}' already found [{}]".format(
book_name, book)
book = Book(book_name=book_name)
for tag in tags:
book.tags.append(tag)
session.add(book)
session.commit()
if __name__ == '__main__':
_insert_test_data()
_add_new_book('SuperMan', ['fiction', 'romance'])