sin*_*ium 3 python postgresql sqlalchemy alembic
我正在开发一个使用 sqlalchemy、postgres 和 alembic 的应用程序。
\n项目结构如下:
.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 alembic.ini\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 main.py\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 migrations\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 env.py\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 README\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 script.py.mako\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 versions\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 models\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 base.py\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 datamodel1.py\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 datamodel2.py\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 requirements.txt\n\n3 directories, 10 files\nRun Code Online (Sandbox Code Playgroud)\n其中:
\n的内容models/base.py是:
from sqlalchemy.ext.declarative.api import declarative_base, DeclarativeMeta\n\nBase: DeclarativeMeta = declarative_base()\nRun Code Online (Sandbox Code Playgroud)\n的内容models/datamodel1.py是:
from models.base import Base\nfrom sqlalchemy.sql.schema import Column\nfrom sqlalchemy.sql.sqltypes import String, Date, Float\n\n\nclass Model1(Base):\n __tablename__ = 'model1_table'\n\n model1_id = Column(String, primary_key=True)\n col1 = Column(String)\n col2 = Column(String)\nRun Code Online (Sandbox Code Playgroud)\n的内容models/datamodel2.py是:
from models.base import Base\nfrom sqlalchemy.orm import relationship\nfrom sqlalchemy.sql.sqltypes import String, Integer, Date\nfrom sqlalchemy.sql.schema import Column, ForeignKey\n\n\n# The many to may relationship table\nclass Model1Model2(Base):\n __tablename__ = 'model1_model2_table'\n\n id = Column(Integer, primary_key=True)\n model_1_id = Column(String, ForeignKey('model1.model1_id'))\n model_2_id = Column(Integer, ForeignKey('model2.model2_id'))\n\n\nclass Model2(Base):\n __tablename__ = 'model2_table'\n\n model2_id = Column(Integer, primary_key=True)\n model2_col1 = Column(String)\n model2_col2 = Column(Date)\n # Many to many relationship\n model1_model2 = relationship('Model1', secondary='model1_model2_table', backref='model1_table')\nRun Code Online (Sandbox Code Playgroud)\n的内容migrations/env.py是:
from logging.config import fileConfig\n\nfrom sqlalchemy import engine_from_config\nfrom sqlalchemy import pool\n\nfrom alembic import context\nimport sys\nsys.path.append('./')\n\n\n\n# this is the Alembic Config object, which provides\n# access to the values within the .ini file in use.\n\nconfig = context.config\n\n# I added the following 2 lines to replace the sqlalchemy.url in alembic.ini file. \ndb_string = f'postgresql+psycopg2://{db_username}:{db_password}@{db_host}:{db_port}/{db_name}'\nconfig.set_main_option('sqlalchemy.url', db_string)\n\n# Interpret the config file for Python logging.\n# This line sets up loggers basically.\nfileConfig(config.config_file_name)\n\n# add your model's MetaData object here\n# for 'autogenerate' support\n# from myapp import mymodel\n# target_metadata = mymodel.Base.metadata\nfrom models.datamodel1 import Model1\nfrom models.datamodel2 import Model2, Model1Model2\nfrom models.base import Base\ntarget_metadata = Base.metadata\n\n# other values from the config, defined by the needs of env.py,\n# can be acquired:\n# my_important_option = config.get_main_option("my_important_option")\n# ... etc.\n\n\ndef run_migrations_offline():\n """Run migrations in 'offline' mode.\n\n This configures the context with just a URL\n and not an Engine, though an Engine is acceptable\n here as well. By skipping the Engine creation\n we don't even need a DBAPI to be available.\n\n Calls to context.execute() here emit the given string to the\n script output.\n\n """\n url = config.get_main_option("sqlalchemy.url")\n context.configure(\n url=url,\n target_metadata=target_metadata,\n literal_binds=True,\n dialect_opts={"paramstyle": "named"},\n include_schemas=True,\n )\n\n with context.begin_transaction():\n context.run_migrations()\n\n\ndef run_migrations_online():\n """Run migrations in 'online' mode.\n\n In this scenario we need to create an Engine\n and associate a connection with the context.\n\n """\n connectable = engine_from_config(\n config.get_section(config.config_ini_section),\n prefix="sqlalchemy.",\n poolclass=pool.NullPool,\n )\n\n with connectable.connect() as connection:\n context.configure(\n connection=connection,\n target_metadata=target_metadata,\n include_schemas=True\n )\n\n with context.begin_transaction():\n context.run_migrations()\n\n\nif context.is_offline_mode():\n run_migrations_offline()\nelse:\n run_migrations_online()\nRun Code Online (Sandbox Code Playgroud)\n至于alembic.ini文件我没有做任何更改,我只是评论了这一行:
sqlalchemy.url = driver://user:pass@localhost/dbname\nRun Code Online (Sandbox Code Playgroud)\n因为我将它分配给migrations/env.py
当我进行更改并运行时,alembic revision --autogenerate -m 'Add new updates'迁移文件会正确生成,并且一切都会按预期进行。
\n但是当我alembic revision --autogenerate -m 'Add new updates'在没有更改的情况下运行时,它会在终端中显示:
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.\nINFO [alembic.runtime.migration] Will assume transactional DDL.\nINFO [alembic.ddl.postgresql] Detected sequence named 'model2_table_model2_id_seq' as owned by integer column 'model2_table(model2_id)', assuming SERIAL and omitting\nINFO [alembic.ddl.postgresql] Detected sequence named 'model1_model2_table_id_seq' as owned by integer column 'model1_model2_table(id)', assuming SERIAL and omitting\n Generating /home/user/projects/dev/project/migrations/versions/45c6fbdbd23c_add_new_updates.py ... done\nRun Code Online (Sandbox Code Playgroud)\n它会生成空的迁移文件,其中包含:
\n"""Add new updates\n\nRevision ID: 45c6fbdbd23c\nRevises: 5c17014a7c18\nCreate Date: 2021-12-27 17:11:13.964287\n\n"""\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '45c6fbdbd23c'\ndown_revision = '5c17014a7c18'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade():\n # ### commands auto generated by Alembic - please adjust! ###\n pass\n # ### end Alembic commands ###\n\n\ndef downgrade():\n # ### commands auto generated by Alembic - please adjust! ###\n pass\n # ### end Alembic commands ###\nRun Code Online (Sandbox Code Playgroud)\n这是预期的行为还是与我的架构有关?
\n如何防止 Alembic 在没有更改的情况下生成那些空的迁移文件?
\n这是预期的行为还是与我的架构有关?
这是预期的行为。命令alembic revision --autogenerate始终创建新的迁移文件。如果不存在任何更改,则会创建一个空更改。
您可以使用alembic-autogen-check来检查您的迁移是否与模型同步。
~ $ alembic-autogen-check
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO: Migrations in sync.
Run Code Online (Sandbox Code Playgroud)
如何防止 Alembic 在没有更改的情况下生成那些空的迁移文件?
alembic-autogen-check仅在迁移与模型同步时才返回零代码。因此,您可以将其用作一个命令
alembic-autogen-check || alembic revision --autogenerate -m 'Add new updates'
Run Code Online (Sandbox Code Playgroud)
但似乎不如单独使用方便
| 归档时间: |
|
| 查看次数: |
3732 次 |
| 最近记录: |