flask_migrate结合geoalchemy2迁移postgis

2024-04-01 00:48

本文主要是介绍flask_migrate结合geoalchemy2迁移postgis,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

代码示例

创建app.py

from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from geoalchemy2 import Geometryapp = Flask(__name__)app.config['SQLALCHEMY_DATABASE_URI'] = "postgresql://postgres:111111@localhost:5432/postgres"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = Falsedb = SQLAlchemy(app)
Migrate(app, db)class Point(db.Model):id = db.Column(db.Integer, primary_key=True, autoincrement=True)geom = db.Column(Geometry("POINT", srid=4326, spatial_index=False))# 正确创建空间索引的方式:指定spatial_index=False,并使用以下方式创建空间索引,否则使用flask_migrate会重复创建索引导致报错
# 参考链接:https://github.com/geoalchemy/geoalchemy2/issues/137#issuecomment-1022413828
db.Index("idx_point_geom",Target.__table__.c.geom,postgresql_using='gist',
)@app.route('/')
def index():return "<h1>hello</h1>"if __name__ == '__main__':app.run(debug=True)

迁移

flask db init

输出:

Creating directory /test/migrations ...  done
Creating directory /test/migrations/versions ...  done
Generating /test/migrations/alembic.ini ...  done
Generating /test/migrations/env.py ...  done
Generating /test/migrations/README ...  done
Generating /test/migrations/script.py.mako ...  done
Please edit configuration/connection/logging settings in '/test/migrations/alembic.ini' before proceeding.
flask db migrate

输出:

INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'point'
INFO  [alembic.autogenerate.compare] Detected removed table 'spatial_ref_sys'
Generating /test/migrations/versions/419c1d992227_.py ...  done
flask db upgrade

输出:

INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 419c1d992227, empty message...File "/test/migrations/versions/419c1d992227_.py", line 23, in upgradesa.Column('geom', geoalchemy2.types.Geometry(geometry_type='POINT', srid=4326, from_text='ST_GeomFromEWKT', name='geometry'), nullable=True),
NameError: name 'geoalchemy2' is not defined

错误分析

发现/test/migrations/versions/419c1d992227_.py中的geoalchemy2没有导入,并且spatial_ref_sys表也不应该被删除,否则将无法使用空间扩展
在这里插入图片描述

解决方案

方法一(推荐):使用geoalchemy2中的alembic_helpers

...
from geoalchemy2.alembic_helpers import include_object, render_itemfrom app import create_app
from app.model import dbapp = create_app()# compare_server_default=True
migrate = Migrate(app, db, compare_type=True, include_object=include_object, render_item=render_item)

方法二:手动编辑

每次迁移完后修改迁移脚本,如下:
在这里插入图片描述
再执行flask db upgrade,输出:

INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 419c1d992227, empty message

迁移成功

修改模板

script.py.mako中添加import geoalchemy2,如下所示:

"""${message}Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}"""
from alembic import op
import sqlalchemy as sa
import geoalchemy2
${imports if imports else ""}# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}def upgrade():${upgrades if upgrades else "pass"}def downgrade():${downgrades if downgrades else "pass"}

env.py中添加include_object函数,忽略spatial_ref_sys表,并在context.configure中添加include_object=include_object,如下所示:

...def include_object(object, name, type_, reflected, compare_to):if type_ == 'table' and name in ('spatial_ref_sys'):return Falsereturn Truedef run_migrations_online():"""Run migrations in 'online' mode.In this scenario we need to create an Engineand associate a connection with the context."""# 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.htmldef 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.')connectable = current_app.extensions['migrate'].db.enginewith connectable.connect() as connection:context.configure(connection=connection,target_metadata=target_metadata,process_revision_directives=process_revision_directives,include_object=include_object,**current_app.extensions['migrate'].configure_args)with context.begin_transaction():context.run_migrations()...       

此方法只在数据库迁移前修改一次,随后可直接进行数据库迁移。

升级

接下来我们来添加一个Polygon

class Polygon(db.Model):id = db.Column(db.Integer, primary_key=True, autoincrement=True)geom = db.Column(Geometry("POLYGON", srid=4326))

迁移后脚本如下:

def upgrade():# ### commands auto generated by Alembic - please adjust! ###op.create_table('polygon',sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),sa.Column('geom', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326, from_text='ST_GeomFromEWKT', name='geometry'), nullable=True),sa.PrimaryKeyConstraint('id'))op.drop_index('idx_point_geom', table_name='point')# ### end Alembic commands ###

其中op.drop_index('idx_point_geom', table_name='point')显然是不对的,因为此操作将会删除空间索引,这不是我们想要的。
回到env.py,添加index判断:

def include_object(object, name, type_, reflected, compare_to):if type_ == 'table' and name in ('spatial_ref_sys'):return Falseif type_ == 'index' and name.endswith("_geom"):return Falsereturn True

总结

  • 在生产环境中,migrations目录应该作为持久化数据永久存储!
  • 对于永久不变的数据库迁移推荐使用db.create_all(),免去了复杂的配置
  • 对于需要添加字段或者新增表的数据库迁移推荐使用修改模板方式,一次配置永久有效

参考链接:

  • https://alembic.sqlalchemy.org/en/latest/autogenerate.html#omitting-table-names-from-the-autogenerate-process
  • https://geoalchemy-2.readthedocs.io/en/latest/alembic.html

这篇关于flask_migrate结合geoalchemy2迁移postgis的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/865810

相关文章

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

Flask 验证码自动生成的实现示例

《Flask验证码自动生成的实现示例》本文主要介绍了Flask验证码自动生成的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习... 目录生成图片以及结果处理验证码蓝图html页面展示想必验证码大家都有所了解,但是可以自己定义图片验证码

Flask解决指定端口无法生效问题

《Flask解决指定端口无法生效问题》文章讲述了在使用PyCharm开发Flask应用时,启动地址与手动指定的IP端口不一致的问题,通过修改PyCharm的运行配置,将Flask项目的运行模式从Fla... 目录android问题重现解决方案问题重现手动指定的IP端口是app.run(host='0.0.

Python结合Flask框架构建一个简易的远程控制系统

《Python结合Flask框架构建一个简易的远程控制系统》这篇文章主要为大家详细介绍了如何使用Python与Flask框架构建一个简易的远程控制系统,能够远程执行操作命令(如关机、重启、锁屏等),还... 目录1.概述2.功能使用系统命令执行实时屏幕监控3. BUG修复过程1. Authorization

在不同系统间迁移Python程序的方法与教程

《在不同系统间迁移Python程序的方法与教程》本文介绍了几种将Windows上编写的Python程序迁移到Linux服务器上的方法,包括使用虚拟环境和依赖冻结、容器化技术(如Docker)、使用An... 目录使用虚拟环境和依赖冻结1. 创建虚拟环境2. 冻结依赖使用容器化技术(如 docker)1. 创

SQL Server数据库迁移到MySQL的完整指南

《SQLServer数据库迁移到MySQL的完整指南》在企业应用开发中,数据库迁移是一个常见的需求,随着业务的发展,企业可能会从SQLServer转向MySQL,原因可能是成本、性能、跨平台兼容性等... 目录一、迁移前的准备工作1.1 确定迁移范围1.2 评估兼容性1.3 备份数据二、迁移工具的选择2.1

使用DeepSeek API 结合VSCode提升开发效率

《使用DeepSeekAPI结合VSCode提升开发效率》:本文主要介绍DeepSeekAPI与VisualStudioCode(VSCode)结合使用,以提升软件开发效率,具有一定的参考价值... 目录引言准备工作安装必要的 VSCode 扩展配置 DeepSeek API1. 创建 API 请求文件2.

将sqlserver数据迁移到mysql的详细步骤记录

《将sqlserver数据迁移到mysql的详细步骤记录》:本文主要介绍将SQLServer数据迁移到MySQL的步骤,包括导出数据、转换数据格式和导入数据,通过示例和工具说明,帮助大家顺利完成... 目录前言一、导出SQL Server 数据二、转换数据格式为mysql兼容格式三、导入数据到MySQL数据

Python结合requests和Cheerio处理网页内容的操作步骤

《Python结合requests和Cheerio处理网页内容的操作步骤》Python因其简洁明了的语法和强大的库支持,成为了编写爬虫程序的首选语言之一,requests库是Python中用于发送HT... 目录一、前言二、环境搭建三、requests库的基本使用四、Cheerio库的基本使用五、结合req

如何用Java结合经纬度位置计算目标点的日出日落时间详解

《如何用Java结合经纬度位置计算目标点的日出日落时间详解》这篇文章主详细讲解了如何基于目标点的经纬度计算日出日落时间,提供了在线API和Java库两种计算方法,并通过实际案例展示了其应用,需要的朋友... 目录前言一、应用示例1、天安门升旗时间2、湖南省日出日落信息二、Java日出日落计算1、在线API2