如何使用Flask / SQLalchemy / Alembic初始化数据库表格?

5

我有一个语言的数据库表,里面存储着相对静态的内容:

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Language(db.Model):
    __tablename__ = 'languages'

    # Fields
    code = db.Column(db.String(2), primary_key=True)
    name = db.Column(db.String(40))
    native = db.Column(db.String(60))
    rtl = db.Column(db.Boolean())  # right to left

数据以CSV格式提供,我想把它插入到数据库中。我能用alembic做到吗?

我使用以下命令初始化所有表(结构和数据):

$ flask db init
$ flask db migrate
$ flask db update

(副问题:这个东西应该首先存储在数据库中,还是作为代码中的CSV文件?我将其用于CMS中,以允许用户指定他们所说的语言/创建的页面所使用的语言。)

我的尝试

提供一个端点,当调用时会添加这个东西:

@app.route('/secret_init_languages')
def db_init_languages():
    from mpu.string import str2bool
    import csv
    path = resource_filename('my_package', 'static/languages.csv')
    nb_languages = 0
    with open(path, 'rt', newline='') as csvfile:
        csvreader = csv.reader(csvfile, delimiter=',')
        next(csvreader, None)  # skip the headers
        for row in csvreader:
            lang = Language(code=row[0],
                            name=row[1],
                            native=row[2],
                            rtl=str2bool(row[3]))
            db.session.add(lang)
            nb_languages += 1
        db.session.commit()
    return 'Added {} languages'.format(nb_languages)

该解决方案的缺点:

  • 我的端点只应该被调用一次
  • 我可能会忘记运行它

Alembic并不是一个数据迁移工具,主要用途不在此。你可以使用Flask-Migrate来更新数据库中的正确表格,但你需要自己移动数据。db = SQLAlchemy()class Language(db.Model):这两个语句对我来说没有意义,除非你同时使用了Flask-SQLAlchemy。 - roganjosh
我认为 db = SQLAlchemy() 不会在应用程序上注册。 - roganjosh
@roganjosh 是的,我使用flask-sqlalchemy。因此我添加了这个标签。当然,我也会执行db.init_app(app) - Martin Thoma
@roganjosh 那么,您的数据迁移工具选择是什么?(我正在使用MySQL数据库) - Martin Thoma
好吧,这让我正在输入答案失效了。现在我不知道你在问什么了。 - roganjosh
一旦架构设置完成,从CSV到数据库的数据迁移可能是一个手动工作。 - roganjosh
1个回答

3

不确定您是否已经解决了这个问题,我曾经使用Flask和SQLAlchemy初始化一个数据库表格时遇到了类似的问题。以下解决方案对我有用(不使用alembic):

from main.app import app
from main.db import db
from models.table import TableModel
from pandas import read_csv

db.init_app(app)

@app.before_first_request
def create_tables():
    db.create_all()
    # Check if the existing table contain data, if not then initialize with csv insert
    s = db.session()
    if len(s.query(TableModel).all()) == 0:
        print('No data in the table detected.')
        print('Initialising the table in database.')
        engine = s.get_bind()
        df = read_csv('./table.csv')
        df.to_sql('table',
                  con=engine,
                  if_exists='append',
                  chunksize=1000,
                  index=False)

app.run(port=5000, debug=True)

注意上面的代码包含在一个名为run.py的脚本中,该脚本从main.app和main.db模块中调用flask应用程序对象和SQLAlchemy对象(来自flask-sqlalchemy)。TableModel是映射到数据库中所需表格的类。我使用了@app.before_first_request装饰器以及pandas.DataFrame.to_sql方法,以便在应用程序最初启动时仅执行一次数据库的初始化(包括从csv插入数据)。虽然我不确定alembic是否对您有要求,但pandas对我很有效,希望这可以帮助您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接