alembic.ini 외부에 alembic 연결 문자열을 저장할 수 있습니까?
SQL Chemy에 Alembic을 사용하고 있습니다.SQLAlchemy에서는 버전 코드로 연결 문자열을 저장하지 않는 패턴을 따르는 경향이 있습니다.에 저는 파일을 있습니다.secret.py
모든 기밀 정보가 포함되어 있습니다.는 이 을 내 이파일이내넣파다습니에일을에 씁니다..gitignore
GitHub에서 끝나지 않습니다.
이 패턴은 잘 작동하지만 이제는 마이그레이션에 알렘빅을 사용하기 시작했습니다.연결 문자열을 숨길 수 없는 것 같습니다. 대에신으로alembic.ini
연결 문자열을 구성 매개 변수로 배치합니다.
# the 'revision' command, regardless of autogenerate
# revision_environment = false
sqlalchemy.url = driver://user:pass@localhost/dbname
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembi
데이터베이스에 대한 사용자 이름/암호 정보가 있는 파일을 실수로 커밋할 수 있습니다.이 연결 문자열을 한 곳에 저장하여 실수로 버전 제어에 커밋할 위험을 피하고 싶습니다.
어떤 선택지가 있습니까?
저는 어제 똑같은 문제를 겪었고 다음과 같은 해결책을 찾았습니다.는 다음작수다니에서 .alembic/env.py
:
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# this will overwrite the ini-file sqlalchemy.url path
# with the path given in the config of the main code
import config as ems_config
config.set_main_option('sqlalchemy.url', ems_config.config.get('sql', 'database'))
ems_config
는 내 구성 데이터를 저장하는 외부 모듈입니다.
config.set_main_option(...)
으로 근적으덮니다어씁로를 덮어씁니다.sqlalchemy.url
의 키[alembic]
의한부의 한 alembic.ini
파일입니다. 제 구성에서는 그냥 검은색으로 남겨둡니다.
위해 수 가장 에 보간 하는 것입니다.alembic.ini
이 을 파일 및이 b) 러한 값설정에 합니다.env.py
레엠빅
sqlalchemy.url = postgresql://%(DB_USER)s:%(DB_PASS)s@35.197.196.146/nozzle-website
env.py
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
# here we allow ourselves to pass interpolation vars to alembic.ini
# fron the host env
section = config.config_ini_section
config.set_section_option(section, "DB_USER", os.environ.get("DB_USER"))
config.set_section_option(section, "DB_PASS", os.environ.get("DB_PASS"))
...
기호 문서에서는 다음을 사용할 것을 권장합니다.create_engine
(코드에서 sqlalchemy.url을 수정하는 대신) 데이터베이스 URL을 사용합니다.
또한 새 URL을 사용하려면 run_migrations_migrations_migrations를 수정해야 합니다. Allan Simon은 블로그에 예제를 가지고 있지만 요약하면 env.py 을 다음과 같이 수정하십시오.
URL을 가져오는 공유 기능을 제공합니다(여기서 URL은 명령줄에서 가져옵니다).
def get_url(): url = context.get_x_argument(as_dictionary=True).get('url') assert url, "Database URL must be specified on command line with -x url=<DB_URL>" return url
오프라인 모드에서 URL 사용:
def run_migrations_offline(): ... url = get_url() context.configure( url=url, target_metadata=target_metadata, literal_binds=True) ...
에서 다을사여 모드서 URL을 합니다.
create_engine
에engine_from_config
:def run_migrations_online(): ... connectable = create_engine(get_url()) with connectable.connect() as connection: ...
그래서 작동하는 것으로 보이는 것은 엔진 생성을 재구현하는 것입니다.env.py
이는 분명히 ini에서 sqlalchemy 연결 문자열을 사용하는 대신 이러한 종류의 사용자 지정을 수행하기 위한 장소입니다.
engine = engine_from_config(
config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool)
자체 엔진 구성을 교체하고 지정할 수 있습니다.
import store
engine = store.engine
sqlalchemy.url - SQLAlchemy를 통해 데이터베이스에 연결하기 위한 URL입니다.이 키는 실제로 개발자가 사용자 지정할 수 있는 파일인 "module" 구성과 관련된 env.py 파일 내에서만 참조됩니다.다중 데이터베이스 구성은 여기서 여러 키에 응답하거나 파일의 다른 섹션을 참조할 수 있습니다.
멀티 데이터베이스에 대한 관리 방법을 잠시 찾고 있었습니다.
여기 제가 한 일이 있습니다.나는 두 개의 데이터베이스를 가지고 있습니다: 로그와 ohlc.
문서에 따르면, 저는 알람을 그렇게 설정했습니다.
alembic init --template multidb
레엠빅
databases = logs, ohlc
[logs]
sqlalchemy.url = postgresql://botcrypto:botcrypto@localhost/logs
[ohlc]
sqlalchemy.url = postgresql://botcrypto:botcrypto@localhost/ohlc
env.py
[...]
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')
# overwrite alembic.ini db urls from the config file
settings_path = os.environ.get('SETTINGS')
if settings_path:
with open(settings_path) as fd:
settings = conf.load(fd, context=os.environ) # loads the config.yml
config.set_section_option("ohlc", "sqlalchemy.url", settings["databases"]["ohlc"])
config.set_section_option("logs", "sqlalchemy.url", settings["databases"]["logs"])
else:
logger.warning('Environment variable SETTINGS missing - use default alembic.ini configuration')
[...]
config.yml
databases:
logs: postgresql://botcrypto:botcrypto@127.0.0.1:5432/logs
ohlc: postgresql://botcrypto:botcrypto@127.0.0.1:5432/ohlc
사용.
SETTINGS=config.yml alembic upgrade head
그것이 도움이 되기를!
MultiDB 설정의 경우(SingleDB의 경우 동일) config를 사용할 수 있습니다.alembic.ini 파일에서 데이터베이스 URL 값을 수정하려면 set_section_option("section"n_name"), 'db_name', 'db_URL')을 지정합니다.
예:
기호의안에
[engine1]
sqlalchemy.url =
[engine2]
sqlalchemy.url =
그리고나서,
env.py
config = context.config
config.set_section_option('engine1', 'sqlalchemy.url', os.environ.get('URL_DB1'))
config.set_section_option('engine2', 'sqlalchemy.url', os.environ.get('URL_DB2'))
env.py :
from alembic.config import Config
alembic_cfg = Config()
alembic_cfg.set_main_option("sqlalchemy.url", getenv('PG_URI'))
https://alembic.sqlalchemy.org/en/latest/api/config.html
로컬 컴퓨터에서 마이그레이션을 실행하고 있기 때문에 이 문제에도 직면했습니다.을 제솔션섹다배것다입니에 넣는 입니다.alembic.ini
데이터베이스 구성(인증 정보 포함)을 저장합니다.
[local]
host = localhost
db = dbname
[test]
host = x.x.x.x
db = dbname
[prod]
host = x.x.x.x
db = dbname
▁the▁in에 .env.py
사용자가 환경을 선택하고 자격 증명을 입력하라는 메시지를 표시할 수 있습니다.
from alembic import context
from getpass import getpass
...
envs = ['local', 'test', 'prod']
print('Warning: Do not commit your database credentials to source control!')
print(f'Available migration environments: {", ".join(envs)}')
env = input('Environment: ')
if env not in envs:
print(f'{env} is not a valid environment')
exit(0)
env_config = context.config.get_section(env)
host = env_config['host']
db = env_config['db']
username = input('Username: ')
password = getpass()
connection_string = f'postgresql://{username}:{password}@{host}/{db}'
context.config.set_main_option('sqlalchemy.url', connection_string)
전체 팀이 액세스할 수 있는 암호 관리자 또는 사용 가능한 구성/비밀 저장소에 자격 증명을 저장해야 합니다.하지만, 이 접근법으로 비밀번호는 당신의 로컬 클립보드에 노출됩니다 - 훨씬 더 나은 접근법은.env.py
구성/비밀 저장소 API에 직접 연결하고 사용자 이름/암호를 직접 꺼내지만 타사 종속성이 추가됩니다.
또 다른 해결책은 템플릿 alembic.ini.dist 파일을 생성하여 버전 코드로 추적하는 것이지만, eembic은 무시합니다.VCS의 ini.
alembic.ini.dist에 기밀 정보를 추가하지 마십시오.
sqlalchemy.url = ...
플랫폼에 코드를 배포할 때 alembic.ini.dist를 alembic.ini에 복사하고(이 파일은 VCS에서 추적되지 않음) 기호를 수정합니다.플랫폼의 자격 증명을 가진 ini.
Doug T.가 말했듯이 env.py 을 편집하여 ini 파일이 아닌 다른 곳에서 URL을 제공할 수 있습니다.새 엔진을 생성하는 대신 추가 엔진을 전달할 수 있습니다.url
의 engine_from_config
함수(나중에 kwarg는 ini 파일에서 가져온 옵션에 병합됨).이 경우 암호화된 암호를 ini 파일에 저장하고 ENV 변수에 저장된 암호 구문을 통해 런타임에 암호를 해독할 수 있습니다.
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool,
url=some_decrypted_endpoint)
가 있었던 은 제게효있옵션은을 사용하는 이었습니다.set_main_option
그리고 그 자리를 떠나십시오.sqlalchemy.url =
의 공백이 있는.alembic.ini
from config import settings
config.set_main_option(
"sqlalchemy.url", settings.database_url.replace("postgres://", "postgresql+asyncpg://", 1))
stings는 env 파일의 변수를 가져오는 데 사용하는 구성 파일의 클래스입니다. 이 os.environment.get()이 창에서 환경 값을 반환하지 않습니까?자세한 내용은 다음을 참조하십시오.
os.environ.get
그러나 sqlalchemy.ex와 같은 오류를 방지하려면 변수를 내보내야 합니다.인수 오류: 문자열에서 rfc1738 URL을 구문 분석할 수 없습니다.
TomDotTom의 답변을 바탕으로 이 솔루션을 고안했습니다.
을 합니다.env.py
파일로 합니다.
config = context.config
config.set_section_option("alembic", "sqlalchemy.url",
os.environ.get("DB_URL", config.get_section_option("alembic", "sqlalchemy.url"))) # type: ignore
이 작업은 다음 작업보다 우선합니다.sqlalchemy.url
의 alembic
에 있습니다.DB_URL
environment variable을 합니다. 그렇지 됩니다.alembic.ini
그런 다음 다른 데이터베이스를 가리키는 마이그레이션을 실행할 수 있습니다.
DB_URL=driver://user:pass@host:port/dbname alembic upgrade head
해서 그고계사용속을 사용하세요.alembic upgrade head
에.
여기서 모든 답을 시도해봤지만 소용이 없었습니다.그럼 아래와 같이 제가 직접 처리하려고 합니다.
.ini 파일:
# A generic, single database configuration.
[alembic]
# path to migration scripts
script_location = alembic
# template used to generate migration files
file_template = %%(rev)s_%%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d_%%(minute).2d_%%(second).2d
# timezone to use when rendering the date
# within the migration file as well as the filename.
# string value is passed to dateutil.tz.gettz()
# leave blank for localtime
# timezone =
# max length of characters to apply to the
# "slug" field
#truncate_slug_length = 40
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
# set to 'true' to allow .pyc and .pyo files without
# a source .py file to be detected as revisions in the
# versions/ directory
# sourceless = false
# version location specification; this defaults
# to alembic/versions. When using multiple version
# directories, initial revisions must be specified with --version-path
# version_locations = %(here)s/bar %(here)s/bat alembic/versions
# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8
databases = auth_engine
[auth_engine]
sqlalchemy.url = mysql+mysqldb://{}:{}@{}:{}/auth_db
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
.env 파일(내 프로젝트의 루트 폴더에 있음):
DB_USER='root'
DB_PASS='12345678'
DB_HOST='127.0.0.1'
DB_PORT='3306'
env.py 파일:
from __future__ import with_statement
import os
import re
import sys
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
DB_USER = os.getenv("DB_USER")
DB_PASS = os.getenv("DB_PASS")
DB_HOST = os.getenv("DB_HOST")
DB_PORT = os.getenv("DB_PORT")
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
# gather section names referring to different
# databases. These are named "engine1", "engine2"
# in the sample .ini file.
db_names = config.get_main_option('databases')
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
sys.path.append(os.path.join(os.path.dirname(__file__), "../../../"))
from db_models.auth_db import auth_db_base
target_metadata = {
'auth_engine': auth_db_base.auth_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.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
engines = {}
for name in re.split(r',\s*', db_names):
engines[name] = rec = {}
section = context.config.get_section(name)
url = section['sqlalchemy.url'].format(DB_USER, DB_PASS, DB_HOST, DB_PORT)
section['sqlalchemy.url'] = url
rec['url'] = url
# rec['url'] = context.config.get_section_option(name, "sqlalchemy.url")
for name, rec in engines.items():
print("Migrating database %s" % name)
file_ = "%s.sql" % name
print("Writing output to %s" % file_)
with open(file_, 'w') as buffer:
context.configure(url=rec['url'], output_buffer=buffer,
target_metadata=target_metadata.get(name),
compare_type=True,
compare_server_default=True
)
with context.begin_transaction():
context.run_migrations(engine_name=name)
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
engines = {}
for name in re.split(r',\s*', db_names):
engines[name] = rec = {}
section = context.config.get_section(name)
url = section['sqlalchemy.url'].format(DB_USER, DB_PASS, DB_HOST, DB_PORT)
section['sqlalchemy.url'] = url
rec['engine'] = engine_from_config(
section,
prefix='sqlalchemy.',
poolclass=pool.NullPool)
for name, rec in engines.items():
engine = rec['engine']
rec['connection'] = conn = engine.connect()
rec['transaction'] = conn.begin()
try:
for name, rec in engines.items():
print("Migrating database %s" % name)
context.configure(
connection=rec['connection'],
upgrade_token="%s_upgrades" % name,
downgrade_token="%s_downgrades" % name,
target_metadata=target_metadata.get(name),
compare_type=True,
compare_server_default=True
)
context.run_migrations(engine_name=name)
for rec in engines.values():
rec['transaction'].commit()
except:
for rec in engines.values():
rec['transaction'].rollback()
raise
finally:
for rec in engines.values():
rec['connection'].close()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
소원은 다른 사람을 도울 수 있습니다.
env.py
덧셈을 하라.
config.set_main_option('sqlalchemy.url', os.environ['DB_URL'])
끝나고
config = context.config
맘에 들다
config = context.config
config.set_main_option('sqlalchemy.url', os.environ['DB_URL'])
다음과 같이 실행합니다.
DB_URL="mysql://atuamae:de4@127.0.0.1/db" \
alembic upgrade head
언급URL : https://stackoverflow.com/questions/22178339/is-it-possible-to-store-the-alembic-connect-string-outside-of-alembic-ini
'source' 카테고리의 다른 글
수동 저장 시 IntelliJ IDEA 봄 부트 핫 새로고침? (0) | 2023.08.15 |
---|---|
결제 게이트웨이에 대한 안내가 필요합니다. (0) | 2023.08.15 |
스프링 부트 & MariaDB - 자동 배선 문제 - 빈을 찾을 수 없음 (0) | 2023.08.10 |
AJAX를 통해 이미지 전달 (0) | 2023.08.10 |
@ImportAutoConfiguration과 @Import의 차이점 (0) | 2023.08.10 |