Flask-SQLAlchemy:未设置SQLALCHEMY_DATABASE_URI或SQLALCHEMY_BINDS.将SQLALCHEMY_DATABASE_URI的默认值设置为"sqlite:///:memory:" [英] Flask-SQLAlchemy: Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. Defaulting SQLALCHEMY_DATABASE_URI to "sqlite:///:memory:"

查看:220
本文介绍了Flask-SQLAlchemy:未设置SQLALCHEMY_DATABASE_URI或SQLALCHEMY_BINDS.将SQLALCHEMY_DATABASE_URI的默认值设置为"sqlite:///:memory:"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是第一次尝试结合flask应用程序工厂模式和pytest框架.我从对sqlite db后端进行基本的健全性测试开始,尽管到目前为止测试工作正常,并且我看到测试db文件已成功创建,但是falsk_sqlalchemy告诉我它没有定义db后端.我试图找到pdb和交互式控制台的问题-一切看起来都很正常.看起来与某种原因有关谁能帮助我了解问题出在哪里?

I am first time trying flask application factory pattern and pytest framework together. I started with a basic sanity test for the sqlite db backend and, although the tests are working fine so far and I see test db file created successfully, the falsk_sqlalchemy is telling me that it doesn't have a db backend defined. I tried to find the problem with pdb and the interactive console - everything looks normal. It looks like it is somehow related to could anyone help me understand where the problem is?

(venv) C:\Users\dv\PycharmProjects\ste-speach-booking>python -m pytest tests/
=========================== test session starts ============================
platform win32 -- Python 3.6.8, pytest-5.1.1, py-1.8.0, pluggy-0.12.0
rootdir: C:\Users\dv\PycharmProjects\ste-speach-booking
collected 3 items

tests\test_models.py ...                                              [100%]

============================= warnings summary =============================
tests/test_models.py::test_init
  C:\Users\d837758\PycharmProjects\ste-speach-booking\venv\lib\site-packages\flask_sqlalchemy\__init__.py:814: UserWarning: Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. Defaulting SQLALCHEMY_DATABASE_URI to "sqlite:///:memory:".
    'Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. '

test_models中的初始测试:

initial tests in the test_models:

import pytest
import src.models
import datetime

def test_ActionTypes(db):
    actiontype1 = src.models.Act_types(action_tyoe='workshop')
    db.session.add(actiontype1)
    db.session.commit()
    actiontype2 = src.models.Act_types(action_tyoe='speech')
    db.session.add(actiontype2)
    db.session.commit()
    count = db.session.query(src.models.Act_types).count()
    assert count is 2

def test_meeting_creation(db):
    meeting = src.models.Meeting(
        _date = datetime.datetime.strptime('2018-12-19', "%Y-%m-%d"),
    )
    db.session.add(meeting)
    db.session.commit()

针对数据库的测试治具:

conftest fixture for the db:

import os
import pytest
import src.config
from src import create_app
from src import db as _db

@pytest.fixture(scope='session')
def db():
    """Session-wide test database."""
    TESTDB_PATH = src.config.testDB
    print(TESTDB_PATH)
    if os.path.exists(TESTDB_PATH):
        os.unlink(TESTDB_PATH)
    app = create_app(config=src.config.TestingConfig)
    with app.app_context():
        _db.create_all()
        yield _db  
        _db.drop_all()
    os.unlink(TESTDB_PATH)

应用工厂:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

def create_app(config=None):
    """Construct the core application."""
    app = Flask(__name__, instance_relative_config=True)
    db.init_app(app)
    if config is None:
        app.config.from_object(config.BaseConfig)
    else:
        app.config.from_object(config)

    with app.app_context():
        # Imports
        from . import routes
        db.create_all()

        return app

config.py:

config.py:

basedir = os.path.abspath(os.path.dirname(__file__))
baseDB = os.path.join(basedir, 'app.db')
devDB =  os.path.join(basedir, 'dev_app.db')
testDB = os.path.join(basedir, 'testing_app.db')

class BaseConfig(object):
    DEBUG = False
    TESTING = False
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
        'sqlite:///' + baseDB
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class TestingConfig(BaseConfig):
    DEBUG = False
    TESTING = True
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
        'sqlite:///' + testDB

推荐答案

问题在于在 create_app()中应用程序组件的配置顺序.

The issue is with the order of configuration of the components of your application in create_app().

调用 db.init_app(app)时,它首先执行的操作是(

When you call db.init_app(app) the first operations it performs are (source):

        if (
            'SQLALCHEMY_DATABASE_URI' not in app.config and
            'SQLALCHEMY_BINDS' not in app.config
        ):
            warnings.warn(
                'Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. '
                'Defaulting SQLALCHEMY_DATABASE_URI to "sqlite:///:memory:".'
            )

认识到该警告吗?

立即在 app.config 中查找所需的配置.该方法继续接受应用程序提供的配置或设置默认值,在这种情况下,默认值为内存数据库.

Immediately it looks in app.config for required configurations. The method goes on to either accept the supplied configuration from the app or set a default, in this case the default is the in memory database.

在实现 create_app()的过程中,对 db.init_app()的调用是在配置应用程序本身之前进行的,

In your implementation of create_app() the call to db.init_app() comes before the app itself is configured, with this:

    db.init_app(app)
    if config is None:
        app.config.from_object(config.BaseConfig)
    else:
        app.config.from_object(config)

直到填充 app.config ,应用程序中都不存在任何 SQLALCHEMY _ 前缀配置,因此当 db.init_app()进入寻找它们,找不到它们,并使用默认值.将 db 的配置移至 app 的配置后即可解决此问题:

Until app.config is populated, none of the SQLALCHEMY_ prefixed configurations exist on the app and so when db.init_app() goes looking for them, they aren't found and the defaults are used. Moving the config of db to after the config of the app fixes the issue:

    if config is None:
        app.config.from_object(config.BaseConfig)
    else:
        app.config.from_object(config)
    db.init_app(app)

这与此问题非常相似,但是我认为您的问题更好值得回答的典型设置示例( create_app()范围和配置方法).

This is quite similar to this question, however I think yours is a better example of a typical setup (scope of create_app() and configuration method) so worth answering.

这篇关于Flask-SQLAlchemy:未设置SQLALCHEMY_DATABASE_URI或SQLALCHEMY_BINDS.将SQLALCHEMY_DATABASE_URI的默认值设置为"sqlite:///:memory:"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆