RuntimeError:“SQLAlchemy”实例已在此 Flask 应用程序上注册

Sco*_*son 5 python flask flask-sqlalchemy

我正在为我的 Flask 应用程序编写一个使用 Flask-SQLAlchemy 的测试。在 中models.py,我使用了db = SQLAlchemy(),并编写了一个函数来使用应用程序对其进行配置。但是当我运行测试时,我收到错误“RuntimeError:“SQLAlchemy”实例已在此 Flask 应用程序上注册”。我不确定测试文件在哪里创建 SQLAlchemy 的新实例。

# flaskr.py
from flask import Flask
from models import setup_db

def create_app(test_config=None):
    app = Flask(__name__)
    setup_db(app)
    return app
Run Code Online (Sandbox Code Playgroud)
# models.py
from flask_sqlalchemy import SQLAlchemy

database_path = "postgresql://student:student@localhost/bookshelf"

db = SQLAlchemy()

def setup_db(app, database_path=database_path):
    app.config["SQLALCHEMY_DATABASE_URI"] = database_path
    db.init_app(app)

    with app.app_context():
        db.create_all()
Run Code Online (Sandbox Code Playgroud)
# test_flaskr.py
import unittest

from flaskr import create_app
from models import setup_db

class BookTestCase(unittest.TestCase):
    def setUp(self):
        self.app = create_app()
        self.client = self.app.test_client()
        setup_db(self.app, "postgresql://student:student@localhost/bookshelf_test")

        with self.app.app_context():
            self.db = SQLAlchemy()
            self.db.init_app(self.app)
            self.db.create_all()

    def test_get_paginated_books(self):
        res = self.client.get("/books")
        data = res.json
        self.assertEqual(res.status_code, 200)
        self.assertTrue(data["success"])
        self.assertTrue(data["total_books"])
        self.assertTrue(len(data["books"]))
Run Code Online (Sandbox Code Playgroud)

当我运行测试时,出现以下错误:

# test_flaskr.py
import unittest

from flaskr import create_app
from models import setup_db

class BookTestCase(unittest.TestCase):
    def setUp(self):
        self.app = create_app()
        self.client = self.app.test_client()
        setup_db(self.app, "postgresql://student:student@localhost/bookshelf_test")

        with self.app.app_context():
            self.db = SQLAlchemy()
            self.db.init_app(self.app)
            self.db.create_all()

    def test_get_paginated_books(self):
        res = self.client.get("/books")
        data = res.json
        self.assertEqual(res.status_code, 200)
        self.assertTrue(data["success"])
        self.assertTrue(data["total_books"])
        self.assertTrue(len(data["books"]))
Run Code Online (Sandbox Code Playgroud)

dav*_*ism 3

Flask-SQLAlchemy 3 会因扩展的常见错误设置而引发错误。db.init_app(app)对于给定的db和实例对,您只能调用一次app。

您db = SQLAlchemy()在 中定义models,然后init_app在 中调用它create_app。您必须使用它db,而不是创建另一个实例。你不能db.init_app再打电话了,已经被叫进来了create_app。

您的测试setUp正在调用create_app,但随后它也会setup_db再次调用,即使它已经作为 的一部分被调用create_app。然后,再往下,您将创建一个新实例self.db = SQLAlchemy(),并init_app使用您已经设置了另一个实例的同一应用程序来调用它。这都是不正确的。

您这样做似乎是因为您正在尝试为测试设置数据库配置。正如Flask 教程中所解释的,这就是create_app函数参数的test_config用途。去掉这个setup_db函数,这是不必要的间接。将您的测试配置传递给工厂以覆盖默认配置。

def create_app(test_config=None):
    app = Flask(__name__)
    app.config.from_mapping(
        SQLALCHEMY_DATABASE_URI="postgresql://student:student@localhost/bookshelf"
    )
    
    if test_config is not None:
        app.config.from_mapping(test_config)

    db.init_app(app)

    with app.app_context():
        db.create_all()

    return app
Run Code Online (Sandbox Code Playgroud)
from flaskr import create_app, db

class BookTestCase(TestCase):
    def setUp(self):
        self.app = create_app({
            "SQLALCHEMY_DATABASE_URI": "postgresql://student:student@localhost/bookshelf_test"
        })
Run Code Online (Sandbox Code Playgroud)

db请注意, in没有直接执行任何操作setUp,它只是导入以在测试期间使用。