著者名と書籍タイトルでフィルタリング
SQLAlchemy で子孫階層に基づいてフィルタリングする方法
SQLAlchemy では、has()
関数を使用して、親エンティティの子孫階層に基づいてクエリをフィルタリングできます。これは、複雑な階層構造を持つエンティティ間の関係をクエリする際に役立ちます。
例
次の例では、Book
エンティティと Author
エンティティ間の関係をモデル化します。
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
engine = create_engine('sqlite:///database.db')
Base = declarative_base()
class Author(Base):
__tablename__ = 'authors'
id = Column(Integer, primary_key=True)
name = Column(String(255))
class Book(Base):
__tablename__ = 'books'
id = Column(Integer, primary_key=True)
title = Column(String(255))
author_id = Column(Integer, ForeignKey('authors.id'))
# Create the tables
Base.metadata.create_all(engine)
上記のコードでは、Book
エンティティは author_id
外部キーを使用して Author
エンティティに関連付けられています。つまり、各書籍には、その書籍を書いた Author
エンティティへの参照が含まれます。
has()
関数を使用して、子孫階層に基づいてクエリをフィルタリングできます。たとえば、Author
エンティティの名前が "John Doe" のすべての書籍を取得するには、次のようにします。
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()
books = session.query(Book).filter(Book.author.has(name="John Doe")).all()
このクエリは、Author
エンティティの名前が "John Doe" であるすべての書籍を返します。
has()
関数は、ネストされたクエリを作成するために使用することもできます。たとえば、Author
エンティティの名前が "John Doe" であり、その書籍のタイトルが "The Great Gatsby" であるすべての書籍を取得するには、次のようにします。
books = session.query(Book).filter(
Book.author.has(name="John Doe", books=Book.has(title="The Great Gatsby"))
).all()
SQLAlchemyで子孫階層に基づいてフィルタリングするサンプルコード
サンプル1:著者名で書籍をフィルタリング
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///database.db')
Base = declarative_base()
class Author(Base):
__tablename__ = 'authors'
id = Column(Integer, primary_key=True)
name = Column(String(255))
class Book(Base):
__tablename__ = 'books'
id = Column(Integer, primary_key=True)
title = Column(String(255))
author_id = Column(Integer, ForeignKey('authors.id'))
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
books = session.query(Book).filter(Book.author.has(name="John Doe")).all()
for book in books:
print(f"書籍名: {book.title}, 著者名: {book.author.name}")
サンプル2:著者名と書籍タイトルでフィルタリング
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///database.db')
Base = declarative_base()
class Author(Base):
__tablename__ = 'authors'
id = Column(Integer, primary_key=True)
name = Column(String(255))
class Book(Base):
__tablename__ = 'books'
id = Column(Integer, primary_key=True)
title = Column(String(255))
author_id = Column(Integer, ForeignKey('authors.id'))
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
books = session.query(Book).filter(
Book.author.has(name="John Doe", books=Book.has(title="The Great Gatsby"))
).all()
for book in books:
print(f"書籍名: {book.title}, 著者名: {book.author.name}")
サンプル3:複数の条件でフィルタリング
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///database.db')
Base = declarative_base()
class Author(Base):
__tablename__ = 'authors'
id = Column(Integer, primary_key=True)
name = Column(String(255))
class Book(Base):
__tablename__ = 'books'
id = Column(Integer, primary_key=True)
title = Column(String(255))
author_id = Column(Integer, ForeignKey('authors.id'))
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
books = session.query(Book).filter(
Book.author.has(
name="John Doe",
or_=Book.author.has(name="Jane Doe")
),
Book.has(
title="The Great Gatsby",
or_=Book.has(title="Pride and Prejudice")
)
).all()
for book in books:
print(f"書籍名: {book.title}, 著者名: {book.author.name}")
サンプル4:ネストされたクエリ
from sqlalchemy import create
SQLAlchemy で子孫階層に基づいてフィルタリングするその他の方法
has()
関数以外にも、SQLAlchemy で子孫階層に基づいてフィルタリングする方法はいくつかあります。
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///database.db')
Base = declarative_base()
class Author(Base):
__tablename__ = 'authors'
id = Column(Integer, primary_key=True)
name = Column(String(255))
class Book(Base):
__tablename__ = 'books'
id = Column(Integer, primary_key=True)
title = Column(String(255))
author_id = Column(Integer, ForeignKey('authors.id'))
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
subquery = session.query(Author).filter(Author.name == "John Doe")
books = session.query(Book).filter(Book.author_id.in_(subquery)).all()
for book in books:
print(f"書籍名: {book.title}, 著者名: {book.author.name}")
このクエリは、Author
エンティティの名前が "John Doe" であるすべての Author
エンティティの ID を取得するサブクエリを作成します。次に、メインクエリを使用して、その ID のいずれかに関連付けられているすべての書籍を取得します。
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///database.db')
Base = declarative_base()
class Author(Base):
__tablename__ = 'authors'
id = Column(Integer, primary_key=True)
name = Column(String(255))
class Book(Base):
__tablename__ = 'books'
id = Column(Integer, primary_key=True)
title = Column(String(255))
author_id = Column(Integer, ForeignKey('authors.id'))
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
books = session.query(Book).join(Author).filter(Author.name == "John Doe").all()
for book in books:
print(f"書籍名: {book.title}, 著者名: {book.author.name}")
このクエリは、Book
エンティティと Author
エンティティを JOIN し、Author
エンティティの名前が "John Doe" であるすべての書籍を取得します。
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///database.db')
Base = declarative_base()
class Author(Base):
__tablename__ = 'authors'
id = Column(Integer, primary_key=True)
name = Column(String(255))
class Book(Base):
__tablename__ = 'books'
id = Column(Integer, primary_key=True)
title = Column(String(255))
author_id = Column(Integer, ForeignKey('authors.id'))
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
books = session.query(Book).filter(
Book.author_id == session.query(Author).filter(Author
sqlalchemy