feat: Integrate Flask-Migrate as a Flask extension and update migration commands to use flask db.

This commit is contained in:
Murilo Scolari 2026-01-31 01:37:44 -03:00
parent 8c4b5462b1
commit 42a4ad3b82
5 changed files with 60 additions and 53 deletions

View file

@ -4,7 +4,7 @@ load_dotenv()
from flask import Flask
from app.config import Config
from app.extensions import db, login_manager
from app.extensions import db, login_manager, migrate
from app.utils import generate_google_maps_url
def create_app(config_class=Config):
@ -13,6 +13,7 @@ def create_app(config_class=Config):
# Initialize Extensions
db.init_app(app)
migrate.init_app(app, db)
login_manager.init_app(app)
login_manager.login_view = 'auth.login'
login_manager.login_message = "Por favor, faça login para acessar esta página."

View file

@ -1,5 +1,7 @@
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_migrate import Migrate
db = SQLAlchemy()
login_manager = LoginManager()
migrate = Migrate()

View file

@ -1,14 +1,9 @@
import logging
from logging.config import fileConfig
from flask import current_app
from alembic import context
import os
import sys
# Adicione o diretório raiz do projeto ao sys.path para importar app
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from app import db, User, Party, Guest # Importe db e seus modelos
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
@ -19,26 +14,41 @@ config = context.config
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')
def get_engine():
try:
# this works with Flask-SQLAlchemy<3 and Alchemical
return current_app.extensions['migrate'].db.get_engine()
except (TypeError, AttributeError):
# this works with Flask-SQLAlchemy>=3
return current_app.extensions['migrate'].db.engine
def get_engine_url():
try:
return get_engine().url.render_as_string(hide_password=False).replace(
'%', '%%')
except AttributeError:
return str(get_engine().url).replace('%', '%%')
# add your model's MetaData object here
# for 'autogenerate' support
target_metadata = db.metadata
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
config.set_main_option('sqlalchemy.url', get_engine_url())
target_db = current_app.extensions['migrate'].db
# 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.
# Configura a URL do banco de dados diretamente da variável de ambiente
DATABASE_URL = os.environ.get('DATABASE_URL')
if not DATABASE_URL:
raise ValueError("A variável de ambiente 'DATABASE_URL' não foi definida. Ela é essencial para a conexão com o PostgreSQL.")
# Algumas plataformas (como Heroku e versões mais antigas do Render) usam "postgres://"
# enquanto o SQLAlchemy espera "postgresql://". Esta linha garante a compatibilidade.
if DATABASE_URL.startswith("postgres://"):
DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql://", 1)
config.set_main_option('sqlalchemy.url', DATABASE_URL)
def get_metadata():
if hasattr(target_db, 'metadatas'):
return target_db.metadatas[None]
return target_db.metadata
def run_migrations_offline():
@ -55,10 +65,7 @@ def run_migrations_offline():
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
url=url, target_metadata=get_metadata(), literal_binds=True
)
with context.begin_transaction():
@ -72,38 +79,35 @@ def run_migrations_online():
and associate a connection with the context.
"""
from sqlalchemy import engine_from_config
from sqlalchemy import pool
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
# this callback is used to prevent an auto-migration from being generated
# when there are no changes to the schema
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
logger.info('No changes in schema detected.')
conf_args = current_app.extensions['migrate'].configure_args
if conf_args.get("process_revision_directives") is None:
conf_args["process_revision_directives"] = process_revision_directives
connectable = get_engine()
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
compare_type=True, # Importante para detectar mudanças de tipo
# this callback is used to prevent an auto-migration from being generated
# when there are no changes to the schema
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
process_revision_directives=process_revision_directives,
target_metadata=get_metadata(),
**conf_args
)
with context.begin_transaction():
context.run_migrations()
def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
logger.info('No changes in schema detected.')
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
run_migrations_online()

View file

@ -1,8 +1,8 @@
"""Reset e criação inicial das tabelas
Revision ID: de7b1978faca
Revision ID: 091bc7ece679
Revises:
Create Date: 2025-07-07 03:10:24.781322
Create Date: 2026-01-31 01:12:37.522590
"""
from alembic import op
@ -10,7 +10,7 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'de7b1978faca'
revision = '091bc7ece679'
down_revision = None
branch_labels = None
depends_on = None

View file

@ -75,16 +75,16 @@ check_success "Limpeza do Banco de Dados"
# --- PASSO 2: CRIAR MIGRAÇÕES ---
echo -e "\n${GREEN}--> PASSO 2: Criando um novo histórico de migrações...${NC}"
echo "Executando: python manage.py db init"
python manage.py db init
echo "Executando: flask db init"
flask db init
check_success "'db init'"
echo "Executando: python manage.py db migrate"
python manage.py db migrate -m "Reset e criação inicial das tabelas"
echo "Executando: flask db migrate"
flask db migrate -m "Reset e criação inicial das tabelas"
check_success "'db migrate'"
echo "Executando: python manage.py db upgrade"
python manage.py db upgrade
echo "Executando: flask db upgrade"
flask db upgrade
check_success "'db upgrade'"