SQLAlchemy:没有这样的表,即使它们是实际创建的

Posted

技术标签:

【中文标题】SQLAlchemy:没有这样的表,即使它们是实际创建的【英文标题】:SQLAlchemy: no such table, even if they are actually created 【发布时间】:2019-01-08 03:31:39 【问题描述】:

我开始使用 TDD 开发 Flask 应用程序。

生产代码和测试都使用与 SQlite 相同的通用 SQLAlchemy 实例,以获得可重用性的好处。

在 __init__.py 中:

db = SQLAlchemy()

因此,测试和实际应用程序都需要访问这个数据库实例,但配置不同:tests.py 使用 /tmp/ 文件来创建虚拟数据。

因此,关于 Flask_SQLAlchemy 文档,我每次使用“db”时都会注意调用正确的应用上下文。

结构:

tests.py
run.py
application/
    __init__.py
    config.py
    models.py
    views.py

这是一些关键代码:

__init.py__

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

from application.models import *

def create_app(conf_object):
    app = Flask(__name__)
    app.config.from_object(conf_object)
    db.init_app(app)
    return (app, db)

tests.py

from flask_sqlalchemy import SQLAlchemy
from application import create_app
import unittest
import os


app, db = create_app('application.config.TestConf') # Test conf: db file will bt a tempfile
from application.models import Update, Update_State, Device, Confirmation
db.create_all(app=app) # Create tables with app context


class APITestCase(unittest.TestCase):

    def setUp(self):
        """Sets up a hardcoded dummy-data database before each test"""

        # Hardcoded fake database

        d1 = Device('1223456789', 'hub', 'R3pTkEAHyUKbUJW7bSK8k5')
        d2 = Device('AZERTY', 'hub', 'R3pTkEAHyUKbUJW7bSK8k5')

        db.session.add(d1)
        db.session.add(d2)

        db.session.commit()

        self.app = app.test_client()

    def tearDown(self):
        """Destroy fake db after each test"""
        os.close(app.config['DB_FD'])
        os.unlink(app.config['DB_FILE'])


    # assert functions

    def test_confirmation_msg_correct(self):
        tester = app.test_client(self)
        response = tester.get('/confirmation-msg', query_string=dict(deviceid='1223456789', updateid='R3pTkEAHyUKbUJW7bSK8k5'), content_type='html/text')
        self.assertEqual(response.status_code, 200)



if __name__ == '__main__':
    with app.app_context(): # Because using using a generic SQLAlchemy() 'db' instance, we need to specify the app. See Flask_sqlalchemy doc, 'Introduction into contexts'
        unittest.main()

models.py

from application import db
import datetime
import shortuuid

class Device(db.Model):
    id = db.Column(db.String(255), primary_key=True)
    type = db.Column(db.String(255))
    version_id = db.Column(db.String(511))

    def __init__(self, id, type, version_id):
        self.id = id
        self.type = type
        self.version_id = version_id

还有其他一些模型,但我保持简单说明。

问题出在 setUp(self) 函数中,其中将虚拟数据添加到数据库中。即使导入了模型并且代码在正确的应用上下文中执行,引擎也找不到表。

没有这样的表:设备

sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlite3.OperationalError) no such table: device [SQL: 'INSERT INTO device (id, type, version_id) VALUES (?, ?, ?)'] [parameters: (('1223456789', 'hub', 'R3pTkEAHyUKbUJW7bSK8k5'), ('AZERTY', 'hub', 'R3pTkEAHyUKbUJW7bSK8k5'))] (Background on this error at: http://sqlalche.me/e/e3q8)

此外,当设置 SQLALCHEMY_ECHO = True 时,这些表显然是用 db.create_all(app=app) 很好地创建的:

2018-07-31 17:06:45,333 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
2018-07-31 17:06:45,333 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,334 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
2018-07-31 17:06:45,334 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,334 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("update__state")
2018-07-31 17:06:45,334 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,335 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("device")
2018-07-31 17:06:45,335 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,335 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("confirmation")
2018-07-31 17:06:45,335 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,335 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("update")
2018-07-31 17:06:45,336 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,336 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE "update" (
    update_id VARCHAR(511) NOT NULL, 
    version VARCHAR(255), 
    description VARCHAR(2047), 
    date_created DATETIME, 
    PRIMARY KEY (update_id)
)


2018-07-31 17:06:45,336 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,349 INFO sqlalchemy.engine.base.Engine COMMIT
2018-07-31 17:06:45,350 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE update__state (
    last_communicated_version_id VARCHAR(255) NOT NULL, 
    PRIMARY KEY (last_communicated_version_id), 
    FOREIGN KEY(last_communicated_version_id) REFERENCES "update" (update_id)
)


2018-07-31 17:06:45,350 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,368 INFO sqlalchemy.engine.base.Engine COMMIT
2018-07-31 17:06:45,376 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE device (
    id VARCHAR(255) NOT NULL, 
    type VARCHAR(255), 
    version_id VARCHAR(511) NOT NULL, 
    PRIMARY KEY (id), 
    FOREIGN KEY(version_id) REFERENCES "update" (update_id)
)


2018-07-31 17:06:45,377 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,387 INFO sqlalchemy.engine.base.Engine COMMIT
2018-07-31 17:06:45,388 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE confirmation (
    id INTEGER NOT NULL, 
    device_id INTEGER, 
    version_id VARCHAR(511) NOT NULL, 
    timestamp DATETIME, 
    PRIMARY KEY (id), 
    UNIQUE (device_id), 
    FOREIGN KEY(device_id) REFERENCES device (id), 
    FOREIGN KEY(version_id) REFERENCES "update" (update_id)
)

希望我清楚,提前谢谢。

【问题讨论】:

你认为 db.createall(app) 什么时候被调用? 在tests.py中。我从 init.py 中删除了 create_all(),并通过调试对其进行了检查。刚刚编辑了帖子 还是同样的错误 【参考方案1】:

已解决

应用程序无法写入由 tempfile.mkstemp() 在 /tmp 中创建的 db 文件。 使用相对本地路径,它可以工作。

【讨论】:

以上是关于SQLAlchemy:没有这样的表,即使它们是实际创建的的主要内容,如果未能解决你的问题,请参考以下文章

sqlalchemy:查询数据库中的现有表

SQLAlchemy Automap不为没有主键的表创建类

SqlAlchemy

退出函数后如何从 ram 中删除 sqlalchemy

tornado 08 数据库-ORM-SQLAlchemy-表关系和简单登录注册

SQLAlchemy