【问题标题】:create_app pattern with flask-sqlalchemy使用 flask-sqlalchemy 创建应用程序模式
【发布时间】:2019-07-12 12:13:33
【问题描述】:

使用 Flask 的应用工厂模式时,我无法在数据库 (PostgresSQL) 中创建表。

我查看了来自 Stackoverflow 和 Flask-SQLAlchemy 源代码的不同示例。我的理解是,使用工厂应用程序模式,I need to set up the so-called context before I can try creating the tables. 但是,当我创建上下文时,Flask 应用程序的配置字典被重置并且它不会向前传播配置。

这是我的model.py

import datetime
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()


class MyModel(db.Model):

    id = db.Column(db.Integer, primary_key=True)
    some = db.Column(db.DateTime, nullable=False)
    random = db.Column(db.String, nullable=False)
    model = db.Column(db.String, nullable=False)
    fields = db.Column(db.Integer, nullable=False)

    def __init__(self, some: datetime.datetime, random: str, model: str,
                 fields: int) -> None:
        self.some = some
        self.random = random
        self.model = model
        self.fields = fields

    def __repr__(self):
        return f"""<MyModel(some={self.some}, random={self.random},
        model={self.model}, fields={self.fields})>"""

这是应用程序的__init__.py 文件

import os

from flask import Flask
from flask_migrate import Migrate
from myapp.models import db

migrate = Migrate()


def create_app(config):

    app = Flask(__name__)
    app.config.from_object(config)
    db.init_app(app)
    migrate.init_app(app, db)
    from .models import MyModel
    with app.app_context():
        db.create_all()

    @app.route('/hello')
    def hello():
        return('Hello World!')

    return app


我还有一个main.py 文件:

from myapp import create_app
from config import Config

app = create_app(Config)

if __name__ == "__main__":
    app.run(host='127.0.0.1', port=8080, debug=True)

根文件夹包含main.pyMyModule 应用程序文件夹。此外,我还在 config.py 文件中设置了 Postgres 实例和所需的配置常量:

import os
from dotenv import load_dotenv

basedir = os.path.abspath(__file__)
load_dotenv(os.path.join(basedir, '.env'))


class Config(object):
    DEBUG = False
    TESTING = False
    CSRF_ENABLED = True
    SECRET_KEY = os.environ.get('SECRET_KEY')
    SQLALCHEMY_DATABASE_URI = os.environ.get('SQLALCHEMY_DATABASE_URI')
    SQLALCHEMY_TRACK_MODIFICATIONS = False

我正在从 .env 文件中读取变量。

当我运行main.py 时,我收到以下错误:

(venv) $:project-name username$ python main.py
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    app = create_app(Config)
  File "/Users/username/project-name/myapp/__init__.py", line 18, in create_app
    db.create_all()
  File "/Users/username/venv/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 1033, in create_all
    self._execute_for_all_tables(app, bind, 'create_all')
  File "/Users/username/venv/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 1025, in _execute_for_all_tables
    op(bind=self.get_engine(app, bind), **extra)
  File "/Users/username/venv/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 956, in get_engine
    return connector.get_engine()
  File "/Users/username/venv/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 560, in get_engine
    options = self.get_options(sa_url, echo)
  File "/Users/username/venv/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 575, in get_options
    self._sa.apply_driver_hacks(self._app, sa_url, options)
  File "/Users/username/venv/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 877, in apply_driver_hacks
    if sa_url.drivername.startswith('mysql'):
AttributeError: 'NoneType' object has no attribute 'drivername'

现在奇怪的是,当我在 create_app 函数中打印 print(app.config) 时,配置已经到位,就像我想要的那样。例如SQLALCHEMY_DATABASE_URI=postgresql://testuser:testpassword@localhost:5432/testdb'。但是,当我在 app.app_context() 循环中打印相同的信息时,SQLALCHEMY_DATABASE_URI=None(例如,其他键值对也被重置)。

我在这里错过了什么?

【问题讨论】:

    标签: python python-3.x flask sqlalchemy flask-sqlalchemy


    【解决方案1】:

    您正在错误地加载您的 .env 文件:

    basedir = os.path.abspath(__file__)
    load_dotenv(os.path.join(basedir, '.env'))
    

    basedir 是模块文件本身,而不是目录。所以对于名为config.py 的文件,basedir 设置为/..absolutepath../config.py,而不是/..absolutepath../config.py。结果,您要求dotenv() 加载文件/..absolutepath../config.py/.env,该文件将不存在。

    您错过了os.path.dirname() 电话:

    basedir = os.dirname(os.path.abspath(__file__))
    

    您可以使用dotenv.find_dotenv() 完全避免这个问题:

    load_dotenv(find_dotenv())
    

    它使用调用它的模块的__file__ 属性。

    其他说明:

    • 您正在使用 Flask-Migrate 来管理架构,因此不要调用 db.create_all()。而是使用 Flask CLI 和 Flask Migrate 命令(flask db initflask db migrateflask db upgrade 创建迁移目录和初始迁移脚本,然后升级连接的数据库以使用最新的架构版本。
    • 如果您从环境变量配置数据库,则不要使用变量配置对象。如果您只是从当前项目中导入config 以获得适用于所有开发的默认配置,那么使用 Flask 应用程序工厂会更容易。您可以随时通过app.config.from_obj() or app.config.from_envvar() 加载更多配置,根据需要使用可选参数和环境变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-17
      • 2019-03-13
      • 2015-06-16
      • 2020-09-26
      • 2022-01-15
      • 1970-01-01
      相关资源
      最近更新 更多