By using this site, you agree to the Privacy Policy and Terms of Use.
Accept
World of SoftwareWorld of SoftwareWorld of Software
  • News
  • Software
  • Mobile
  • Computing
  • Gaming
  • Videos
  • More
    • Gadget
    • Web Stories
    • Trending
    • Press Release
Search
  • Privacy
  • Terms
  • Advertise
  • Contact
Copyright © All Rights Reserved. World of Software.
Reading: How to Set Up Session-Level Database Migrations in Python | HackerNoon
Share
Sign In
Notification Show More
Font ResizerAa
World of SoftwareWorld of Software
Font ResizerAa
  • Software
  • Mobile
  • Computing
  • Gadget
  • Gaming
  • Videos
Search
  • News
  • Software
  • Mobile
  • Computing
  • Gaming
  • Videos
  • More
    • Gadget
    • Web Stories
    • Trending
    • Press Release
Have an existing account? Sign In
Follow US
  • Privacy
  • Terms
  • Advertise
  • Contact
Copyright © All Rights Reserved. World of Software.
World of Software > Computing > How to Set Up Session-Level Database Migrations in Python | HackerNoon
Computing

How to Set Up Session-Level Database Migrations in Python | HackerNoon

News Room
Last updated: 2025/11/10 at 2:02 PM
News Room Published 10 November 2025
Share
How to Set Up Session-Level Database Migrations in Python | HackerNoon
SHARE

Following my previous post about setting a function-level database setup, which is a junior-level solution, we’ll be looking at a session-level database migration setup.

When initiating a DB-coupled application, one of the initial goals is to set a DB connection function or class for spawning a reliable asynchronous connection with our DB.

Let us cover the most important parts of our setup.

The DB session manager class:

from sqlalchemy.ext.asyncio import (
    async_sessionmaker,
    create_async_engine,
    AsyncEngine,
    AsyncSession,
)


class DBSessionManager:
    def __init__(self, postgres_dsn: str):
        self._engine: AsyncEngine = create_async_engine(url=postgres_dsn)
        self._async_sesionmaker = async_sessionmaker(
            bind=self._engine, expire_on_commit=False
        )

    @property
    def asessionmaker(self) -> async_sessionmaker[AsyncSession]:
        return self._async_sesionmaker

    async def close(self):
        await self._engine.dispose()

With the same set of models:

class Product(Base):
    __tablename__ = 'product'

    id: Mapped[UUID] = mapped_column(
        type_=types.UUID,
        primary_key=True,
        server_default=text('gen_random_uuid()'),
    )
    name: Mapped[str] = mapped_column(
        type_=types.VARCHAR(100), server_default=text("''")
    )
    created_at: Mapped[timestamp] = mapped_column(
        type_=types.TIMESTAMP,
        server_default=text('NOW()'),
    )


class Review(Base):
    __tablename__ = 'review'

    id: Mapped[UUID] = mapped_column(
        type_=types.UUID,
        primary_key=True,
        server_default=text('gen_random_uuid()'),
    )
    content: Mapped[str] = mapped_column(
        type_=types.VARCHAR(1000), server_default=text("''")
    )
    rating: Mapped[int] = mapped_column(type_=types.DECIMAL(2, 1))
    created_at: Mapped[timestamp] = mapped_column(
        type_=types.TIMESTAMP,
        server_default=text('NOW()'),
    )

:::info
Note: the test setup file is still the bottleneck of our test environment setup.

:::

The Essence of the Fixture Setup

The key fixtures to implement in a Python application with a database connection include:

  • Database creation and teardown
  • Schema version upgrades and downgrades
  • Connection setup and database content reset
@pytest_asyncio.fixture(scope="session")
async def create_test_db(os_environ_patch):
    test_db_name="example_db_test"
    engine = create_async_engine(
        os.environ['POSTGRES_DSN_ORIGINAL'],
        isolation_level="AUTOCOMMIT",
    )

    create_db_op = text(f'CREATE DATABASE {test_db_name}')
    drop_db_op = text(f'DROP DATABASE IF EXISTS {test_db_name} WITH (FORCE)')
    async with engine.begin() as conn:
        await conn.execute(create_db_op)

    yield
    async with engine.connect() as conn:
        await conn.execute(drop_db_op)


@pytest.fixture(scope="session")
def migrate_db(create_test_db):
    config = Config('alembic.ini')
    test_db_url = os.environ['POSTGRES_DSN']
    config.set_main_option('sqlalchemy.url', test_db_url)
    command.upgrade(config, 'head')
    yield
    command.downgrade(config, 'base')


@pytest_asyncio.fixture
async def db(migrate_db) -> AsyncGenerator[DBSessionManager, None]:
    postgres_dsn = os.environ['POSTGRES_DSN']
    db_manager = DBSessionManager(postgres_dsn)
    yield db_manager
    target_metadata = Base.metadata
    tables = target_metadata.tables.keys()
    all_tables_str=", ".join(f'"{t}"' for t in tables)
    async with db_manager.asessionmaker() as s:
        await s.execute(text(f'TRUNCATE TABLE {all_tables_str} CASCADE'))
        await s.commit()
    await db_manager.close()

Now, let’s zoom in on the most important parts.

Migrations

@pytest.fixture(scope="session")
def migrate_db(create_test_db):

The above lets us run through the migration step only once per session.

Tables truncation

Here, the DB fixture is relying on the session manager to execute custom SQL transactions.

    target_metadata = Base.metadata
    tables = target_metadata.tables.keys()   # dict_keys(['product', 'review'])
    all_tables_str=", ".join(f'"{t}"' for t in tables)   # '"product", "review"'

The code above extracts the registered tables to the comma-separated and quotation marks-wrapped representation.

After that, TRUNCATE TABLE {all_tables_str} CASCADE will delete all the records in the tables using cascade mode by deleting records in the constraints-dependent tables.

The final step is to dispose of the DB manager instance

    await db_manager.close()

This way, we are ensured the migration process is set up correctly within our Python application.

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Twitter Email Print
Share
What do you think?
Love0
Sad0
Happy0
Sleepy0
Angry0
Dead0
Wink0
Previous Article Tesla Cybertruck and Model 3 program manager steps down Tesla Cybertruck and Model 3 program manager steps down
Next Article 9 Walmart Electronics That Customers Swear By – BGR 9 Walmart Electronics That Customers Swear By – BGR
Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Stay Connected

248.1k Like
69.1k Follow
134k Pin
54.3k Follow

Latest News

4 Cool New USB-A Mini Gadgets You Never Knew You Needed – BGR
4 Cool New USB-A Mini Gadgets You Never Knew You Needed – BGR
News
‘I didn’t have anything to prove’: what Traitors finalist Jade Scott learned about survival from video games
‘I didn’t have anything to prove’: what Traitors finalist Jade Scott learned about survival from video games
News
This weird smart ring looks like a smartwatch, and even doubles as one
This weird smart ring looks like a smartwatch, and even doubles as one
News
How to improve Brand visibility in AI search engines
How to improve Brand visibility in AI search engines
Gadget

You Might also Like

Linux 6.19-rc8 Released Ahead Of Linux 6.19 Stable Next Week
Computing

Linux 6.19-rc8 Released Ahead Of Linux 6.19 Stable Next Week

1 Min Read
Microsoft’s historic plunge: Why the company lost 7 billion in value despite strong results
Computing

Microsoft’s historic plunge: Why the company lost $357 billion in value despite strong results

7 Min Read
Generic interfaces: When to Use Them | HackerNoon
Computing

Generic interfaces: When to Use Them | HackerNoon

23 Min Read
The HackerNoon Newsletter: AI Doesn’t Mean the End of Work for Us (2/1/2026) | HackerNoon
Computing

The HackerNoon Newsletter: AI Doesn’t Mean the End of Work for Us (2/1/2026) | HackerNoon

3 Min Read
//

World of Software is your one-stop website for the latest tech news and updates, follow us now to get the news that matters to you.

Quick Link

  • Privacy Policy
  • Terms of use
  • Advertise
  • Contact

Topics

  • Computing
  • Software
  • Press Release
  • Trending

Sign Up for Our Newsletter

Subscribe to our newsletter to get our newest articles instantly!

World of SoftwareWorld of Software
Follow US
Copyright © All Rights Reserved. World of Software.
Welcome Back!

Sign in to your account

Lost your password?