db.create_all() 在磁盘上但不在内存中创建模式

Posted

技术标签:

【中文标题】db.create_all() 在磁盘上但不在内存中创建模式【英文标题】:db.create_all() Creates Schema on Disk But Not in Memory 【发布时间】:2021-11-12 18:08:24 【问题描述】:

我正在尝试按照 Harry Percival 书中的模式为我正在编写的 Flask 联系人管理器应用程序开发功能/集成测试。为了测试,我想创建一个 sqlite3 内存数据库,但对 db.create_all() 的调用不会创建我的模式,即使相同的调用适用于磁盘上的 sqlite3 数据库。我的代码:

config.py

import os

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

class Config(object):
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'Hard to guess string'

    SQLALCHEMY_TRACK_MODIFICATIONS = False
    
    LOG_TO_STDOUT = False
    
    @staticmethod
    def init_app(app):
        pass

class TestConfig(Config):
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
    SQLALCHEMY_TRACK_MODIFICATIONS = True

class DevConfig(Config):
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db')
    SQLALCHEMY_TRACK_MODIFICATIONS = True


config = 
    'development': DevConfig,
    'testing': TestConfig,
    
    'default': DevConfig

app/__init__.py

import os
from flask import Flask
from flask_bootstrap import Bootstrap
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy

import logging
from logging.handlers import RotatingFileHandler

from config import config


db = SQLAlchemy()
migrate = Migrate()
bootstrap = Bootstrap()


def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)
    
    db.init_app(app)
    migrate.init_app(app, db)
    bootstrap.init_app(app)
    
    from app.main import main as main_blueprint
    app.register_blueprint(main_blueprint)
    from app.contacts import contacts as contacts_blueprint
    app.register_blueprint(contacts_blueprint, url_prefix='/contacts')
    from app.auth import auth as auth_blueprint
    app.register_blueprint(auth_blueprint, url_prefix='/auth')
    
    if app.config['LOG_TO_STDOUT']:
        stream_handler = logging.StreamHandler()
        stream_handler.setLevel(logging.INFO)
        app.logger.addHandler(stream_handler)
    else:
        if not os.path.exists('logs'):
            os.mkdir('logs')
        
        file_handler = RotatingFileHandler('logs/contacts.log', maxBytes=10240, backupCount=10)
        file_handler.setFormatter(logging.Formatter(
            '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
        ))
        file_handler.setLevel(logging.INFO)
        app.logger.addHandler(file_handler)
    
    app.logger.setLevel(logging.DEBUG)
    app.logger.info('Contacts startup')
    
    return app

from app import models

functional_tests.py

import unittest
from flask_testing import LiveServerTestCase
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

from app import create_app, db
from app.models import Contact


class NewVisitorTest(LiveServerTestCase):
    
    def create_app(self):
        # app = create_app('development')
        app = create_app('testing')
        return app
    
    def setUp(self):
        self.app = self.create_app()
        self.browser = webdriver.Firefox()
        db.create_all()

    def tearDown(self):
        self.browser.quit()
        db.session.remove()
        db.drop_all()
    
    def test_can_enter_new_contact_and_retreive_it_later(self):
        # Edith has recently joined the IBS Communications Committee, and wants to look
        # up information on one of the Society's contacts.
        # She has been told about the Contact Manager application, and decides to try it
        # out. She attempts to access the application.
        self.browser.get(self.get_server_url())

        # testing fails, development succeeds

当我使用development 配置运行此测试时,该配置使用磁盘上的sqlite 数据库,db.create_all() 成功并且测试通过;当我使用testing 配置时,它会失败并显示以下回溯:

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: contacts
[SQL: SELECT contacts.id AS contacts_id, contacts.email AS contacts_email, contacts.firstname AS contacts_firstname, contacts.lastname AS contacts_lastname, contacts.phone AS contacts_phone, contacts.seller_id AS contacts_seller_id, contacts.blacklisted AS contacts_blacklisted, contacts.disabled AS contacts_disabled, contacts.is_member AS contacts_is_member, contacts.membership_date AS contacts_membership_date 
FROM contacts ORDER BY contacts.id ASC]
(Background on this error at: https://sqlalche.me/e/14/e3q8)

我检查了SQLALCHEMY_ECHO = True,SQLAlchemy 正在生成完整的CREATE TABLE 语句集,以COMMIT 结尾,并且生成的 SQL 在测试用例之间是相同的。

【问题讨论】:

有人投票决定关闭,因为我的问题“缺乏调试细节”。也许你可以告诉我你还想要什么其他细节? 也许显示你的工厂函数'create_app',看看你是如何实例化db对象的,它用简单的话告诉你它没有找到表的错误,所以你的模型可能不是测试前被db对象发现 @SebastianSalinasDelRio 我已按您的要求添加了我的app/__init__.py 文件。令人气愤的是,当我将测试数据库更改为磁盘数据库时,整个事情就开始工作了,但是如果我切换回内存,它仍然无法工作,即使它在我所有其他教程中都有效完毕。不过,这只是一种解决方法,我非常喜欢一个实际的解决方案。 据我所知,您的导入存在问题,主要是在 init.py 中,您在文件底部导入模型,我复制了一个 mini您的应用程序的版本,我收到很多导入错误。所以我推荐以下提示:__init__.py 提取db 对象,以便您可以安全地导入它 创建一个应用程序运行器并在那里建立迁移扩展 导入您的模型在您的 create_app 功能之前如果您需要更多帮助,我们可以更广泛地交谈。 @SebastianSalinasDelRio 这不会导致磁盘数据库出现同样的问题吗?它没有。 【参考方案1】:

错误出现在您的 DATABASE URI 中,在 TestConfig 类上,为了在内存数据库中建立临时性,正确的 URI 是:'sqlite://' NOT 'sqlite:///:memory:'

您好!

【讨论】:

那行不通。 我的内存测试使用'sqlite://'。你看到了什么错误? 无论我使用sqlite:// 还是sqlite:///:memory:,都会看到与上面显示的完全相同的错误。

以上是关于db.create_all() 在磁盘上但不在内存中创建模式的主要内容,如果未能解决你的问题,请参考以下文章

SSLHandshakeException CertPathValidatorException 在 Android 2.3 上但不在 Android 4 上

Fontawesome 图标显示在桌面上但不在移动设备上

碰撞工作在PC模拟器上但不在Android设备上

ORA-00947 - 没有足够的值: 发生在一个服务器上但不在另一个服务器上

在内存中压缩多个目录和文件,而不在磁盘上存储 zip

flask-migrate