Migrations

Let’s learn to perform migrations in databases.

We need a way to create tables that correspond to the objects defined in rentomatic/repository/postgres_objects.py.

Alembic

The best strategy when we use an ORM like SQLAlchemy is to create and run migrations. For this, we can use Alembic.

Perform migrations using Alembic

First of all, let’s initialize Alembic. In the project’s main directory (where manage.py is stored), let’s run the command below:

$ alembic init migrations

The command above creates a directory called migrations that contains Alembic’s configuration files and the migrations that will be created in migrations/versions. It also creates the alembic.ini file, which contains the configuration values. The name migrations is completely arbitrary, so we can also choose to use a different one if we prefer.

Set environment variable requirement

The specific file we need to adjust to make Alembic aware of our models and our database is migrations/env.py.

Press + to interact
import os
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
section = config.config_ini_section
config.set_section_option(
section, "POSTGRES_USER", os.environ.get("POSTGRES_USER")
)
config.set_section_option(
section, "POSTGRES_PASSWORD", os.environ.get("POSTGRES_PASSWORD")
)
config.set_section_option(
section, "POSTGRES_HOSTNAME", os.environ.get("POSTGRES_HOSTNAME")
)
config.set_section_option(
section, "APPLICATION_DB", os.environ.get("APPLICATION_DB")
)
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
# target_metadata = None
from rentomatic.repository.postgres_objects import Base
target_metadata = Base.metadata
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.

Through config.set_section_option, we add relevant configuration values to the main Alembic INI file section, config.config_ini_section, extracting them from the environment variables. We also import the file that contains the SQLAlchemy objects.

Configure Alembic

We can find documentation on configuring Alembic at https://alembic.sqlalchemy.org/en/latest/api/config.html.

Once Alembic is configured, we need to change the alembic.ini file to use the new variables as follows:

Press + to interact
# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8
sqlalchemy.url = postgresql://%(POSTGRES_USER)s:%(POSTGRES_PASSWORD)s@%(POSTGRES_HOSTNAME)s/%(APPLICATION_DB)s
[post_write_hooks]
# post_write_hooks defines scripts or Python functions that are run
# on newly generated revision scripts. See the documentation for further
# detail and examples

The %(VARNAME)s syntax is the basic variable interpolation used by ConfigParser (see the ...