Etikett: Python

  • Skapa Databasmigreringar med Alembic i Python

    Skapa Databasmigreringar med Alembic i Python

    Jag går en kurs i Python, programmeringsspråket. En av de sista uppgifterna är att skapa en hemsida, egentligen en portfolio med program jag skapat och länkar till Github med flera ställen där jag har något jag vill visa upp. I kursen använde vi SQLite som databas men eftersom jag använd MySql mycket i mina andra projekt så ville jag göra det här med. Plus att det blev en liten utmaning att göra om databaskopplingar.

    För att på ett enkelt sätt kunna göra databasmigreringar när jag uppgraderar mitt program hittade jag Alembic som fungerar bra för det. Sökvägarna behöver rättas utifrån varje projekt, förstås men gången är denna:


    1. Installera Alembic

    Om du inte redan har det:

    pip install alembic

    2. Initiera Alembic

    I roten av ditt projekt (där din app/-mapp och run.py eller liknande ligger):

    alembic init migrations

    Det skapar en migrations/-mapp och en alembic.ini-fil.


    3. Konfigurera alembic.ini

    Öppna alembic.ini och ändra denna rad:

    sqlalchemy.url = driver://user:pass@localhost/dbname

    Byt ut den mot din databas-url, t.ex.:

    sqlalchemy.url = mysql+pymysql://root:password@localhost/portfolio-db

    Eller om du använder en .env-fil – då ändrar vi detta i steg 5 istället via Python.


    4. Peka Alembic till din SQLAlchemy-modell

    Öppna migrations/env.py och leta upp detta block:

    from logging.config import fileConfig
    from sqlalchemy import engine_from_config, pool
    from alembic import context

    Lägg till din models.py-import (efter importerna ovan):

    import sys
    import os
    sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
    from app.models import db # Lägg till detta

    Byt ut denna rad:

    target_metadata = None

    mot:

    target_metadata = db.metadata

    5. (Valfritt) Använd din DATABASE_URL från .env

    Om du vill använda os.getenv("DATABASE_URL"):

    Byt ut i migrations/env.py (under config = context.config):

    from dotenv import load_dotenv
    load_dotenv()
    from sqlalchemy.engine.url import URL
    config.set_main_option("sqlalchemy.url", os.getenv("DATABASE_URL"))

    6. Skapa en migrering

    När du ändrar en modell (t.ex. la till description i PortfolioItem), kör:

    alembic revision --autogenerate -m "Add description to portfolio item"

    Det skapar en versionsfil i migrations/versions/.


    7. Kör migreringen

    alembic upgrade head

    Nu har kolumnen description skapats i databasen utan att radera något!


    alembic.ini

    Byt ut din befintliga alembic.ini med denna:

    [alembic]
    script_location = migrations
    sqlalchemy.url = mysql+pymysql://root:password@localhost/portfolio-db

    [loggers]
    keys = root,sqlalchemy,alembic

    [handlers]
    keys = console

    [formatters]
    keys = generic

    [logger_root]
    level = WARN
    handlers = console

    [logger_sqlalchemy]
    level = WARN
    handlers =
    qualname = sqlalchemy.engine

    [logger_alembic]
    level = INFO
    handlers =
    qualname = alembic

    [handler_console]
    class = StreamHandler
    args = (sys.stdout,)
    level = NOTSET
    formatter = generic

    [formatter_generic]
    format = %(levelname)-5.5s [%(name)s] %(message)s

    Byt root:password om du har en annan användare eller databas.


    migrations/env.py

    Byt ut hela innehållet i migrations/env.py med detta:

    from __future__ import with_statement

    import sys
    import os
    from logging.config import fileConfig
    from sqlalchemy import engine_from_config, pool
    from alembic import context

    # Lägg till appens rot till sys.path
    sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

    # Importera extensions och modeller
    from app.extensions import db
    from app.models import *

    # Load environment variables
    from dotenv import load_dotenv
    load_dotenv()

    # Alembic Config
    config = context.config

    # Sätt databas-URL från .env
    config.set_main_option('sqlalchemy.url', os.getenv("DATABASE_URL"))

    # Loggkonfiguration
    fileConfig(config.config_file_name)

    # Metadata från modellerna
    target_metadata = db.metadata

    def run_migrations_offline():
    """Kör migreringar utan en DB-anslutning."""
    url = config.get_main_option("sqlalchemy.url")
    context.configure(
    url=url,
    target_metadata=target_metadata,
    literal_binds=True,
    dialect_opts={"paramstyle": "named"},
    )

    with context.begin_transaction():
    context.run_migrations()

    def run_migrations_online():
    """Kör migreringar med en DB-anslutning."""
    connectable = engine_from_config(
    config.get_section(config.config_ini_section),
    prefix="sqlalchemy.",
    poolclass=pool.NullPool,
    )

    with connectable.connect() as connection:
    context.configure(
    connection=connection,
    target_metadata=target_metadata
    )

    with context.begin_transaction():
    context.run_migrations()

    if context.is_offline_mode():
    run_migrations_offline()
    else:
    run_migrations_online()

    Klar att köra:

    Nu kan du köra:

    alembic revision --autogenerate -m "Add description field"
    alembic upgrade head

    Relaterade bilder: