[파이썬] SQLAlchemy Advanced Many-to-Many Patterns

In today’s blog post, we will explore some advanced many-to-many patterns using SQLAlchemy, a powerful Python library for working with relational databases. Many-to-many relationships are common in database design when two entities can be associated with multiple instances of each other. SQLAlchemy provides elegant and flexible ways to handle such relationships.

Setting up the Environment

Before we start, make sure you have SQLAlchemy installed in your Python environment. You can install it using pip:

pip install sqlalchemy

Additionally, you will need a database system, such as MySQL or PostgreSQL, to follow along with the examples. Make sure you have a database server running and create a new database for our tests.

Scenario: Bookstore and Authors

To illustrate the advanced many-to-many patterns, let’s consider the following scenario: a bookstore and its authors. Each author can write multiple books, and each book can have multiple authors. We will create a database schema to model this relationship using SQLAlchemy.

Defining the Database Schema

In SQLAlchemy, we can define the database schema using Python classes that inherit from the Base class provided by SQLAlchemy. Let’s create three classes: Author, Book, and AuthorBook.

from sqlalchemy import Column, Integer, String, ForeignKey, Table
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Author(Base):
    __tablename__ = 'authors'
    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False)

class Book(Base):
    __tablename__ = 'books'
    id = Column(Integer, primary_key=True)
    title = Column(String(100), nullable=False)

author_book = Table(
    'author_book',
    Base.metadata,
    Column('author_id', ForeignKey('authors.id'), primary_key=True),
    Column('book_id', ForeignKey('books.id'), primary_key=True)
)

In this schema, we have defined the Author and Book classes as regular SQLAlchemy models with their respective columns. The AuthorBook class represents the many-to-many relationship between authors and books using a custom table defined using SQLAlchemy’s Table class.

Setting up the Database Session

To interact with the database, we need to create a session object. SQLAlchemy provides an ORM feature for managing the database session. We can create a session using the sessionmaker class.

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

engine = create_engine('DATABASE_URL')
Session = sessionmaker(bind=engine)
session = Session()

Replace 'DATABASE_URL' with the URL of your database server. For example, if you’re using MySQL, the URL might look like 'mysql://username:password@localhost/db_name'.

Adding Many-to-Many Relationship to Models

To establish the many-to-many relationship between Author and Book models, we need to add a relationship attribute to both models, pointing to the AuthorBook table.

class Author(Base):
    # ...

    books = relationship(
        "Book",
        secondary=author_book,
        back_populates="authors"
    )

class Book(Base):
    # ...

    authors = relationship(
        "Author",
        secondary=author_book,
        back_populates="books"
    )

By specifying secondary=author_book, we inform SQLAlchemy to use the AuthorBook table as the intermediary table for the relationship. The back_populates parameter establishes the bidirectional relationship between Author and Book models.

Performing CRUD Operations

Now that we have set up the database schema and established the many-to-many relationship, we can perform CRUD (Create, Read, Update, Delete) operations on our models.

Creating Data

To create a new author and a new book and associate them together, we can use the following code:

author1 = Author(name="John Doe")
book1 = Book(title="Book 1")

author1.books.append(book1)

session.add(author1)
session.commit()

Here, we create an instance of Author and Book. We then add the book to the author’s books attribute using the append method and finally add the author to the session and commit the changes.

Querying Data

To query authors and their associated books, we can use the following code:

authors = session.query(Author).all()

for author in authors:
    print(f"Author: {author.name}")
    for book in author.books:
        print(f"- {book.title}")

This code retrieves all authors from the database and prints their names along with the titles of their associated books.

Updating and Deleting Data

To update or delete data, we can simply update or delete the desired objects and commit the changes. For example, to delete an author and their associated books:

author_to_delete = session.query(Author).first()

session.delete(author_to_delete)
session.commit()

This code deletes the first author returned by the query along with their associated books from the database.

Conclusion

In this blog post, we explored advanced many-to-many patterns using SQLAlchemy in Python. We learned how to set up the database schema, create the many-to-many relationship, and perform CRUD operations on the models. SQLAlchemy provides a powerful and flexible solution for working with complex relationships in your database. Feel free to explore more advanced features and optimizations that SQLAlchemy offers for handling many-to-many relationships.