属性错误:使用Flask-SQLAlchemy连接SQLite数据库时无法设置属性。

32
我一直在学习 Flask Web 应用程序框架,并对它感到非常舒适。我以前构建过一个简单的待办事项应用程序,它可以完美地工作。我正在尝试使用 TDD 实现同一个项目,但是遇到了一个我从未见过且不知道如何解决的数据库错误。
当我检查我的代码时,我没有发现任何问题。它看起来与工作中的项目代码完全相同,所以我真的不知道自己做错了什么。
以下是错误信息:
(env) PS C:\coding-projects\task-master-tdd> flask shell
Python 3.8.5 (tags/v3.8.5:580fbb0, Jul 20 2020, 15:43:08) [MSC v.1926 32 bit (Intel)] on win32
App: project [development]
Instance: C:\coding-projects\task-master-tdd\instance
>>> from project import db
>>> db
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "c:\coding-projects\task-master-tdd\env\lib\site-packages\flask_sqlalchemy\__init__.py", line 1060, in __repr__
    self.engine.url if self.app or current_app else None
  File "c:\coding-projects\task-master-tdd\env\lib\site-packages\flask_sqlalchemy\__init__.py", line 943, in engine
    return self.get_engine()
  File "c:\coding-projects\task-master-tdd\env\lib\site-packages\flask_sqlalchemy\__init__.py", line 962, in get_engine
    return connector.get_engine()
  File "c:\coding-projects\task-master-tdd\env\lib\site-packages\flask_sqlalchemy\__init__.py", line 555, in get_engine
    options = self.get_options(sa_url, echo)
  File "c:\coding-projects\task-master-tdd\env\lib\site-packages\flask_sqlalchemy\__init__.py", line 570, in get_options
    self._sa.apply_driver_hacks(self._app, sa_url, options)
  File "c:\coding-projects\task-master-tdd\env\lib\site-packages\flask_sqlalchemy\__init__.py", line 914, in apply_driver_hacks
    sa_url.database = os.path.join(app.root_path, sa_url.database)
AttributeError: can't set attribute
>>>

我的config.py文件:

import os

# load the environment variables from the .env file
from dotenv import load_dotenv
load_dotenv()

# Determine the folder of the top-level directory of this project
BASEDIR = os.path.abspath(os.path.dirname(__file__))


class Config:
    FLASK_ENV = 'development'
    TESTING = False
    DEBUG = False
    SECRET_KEY = os.getenv('SECRET_KEY', default='A very terrible secret key.')
    SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URL',
                                        default=f"sqlite:///{os.path.join(BASEDIR, 'instance', 'app.db')}")
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class DevelopmentConfig(Config):
    DEBUG = True

class TestingConfig(Config):
    TESTING = True
    SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URL',
                                        default=f"sqlite:///{os.path.join(BASEDIR, 'instance', 'test.db')}")

class ProductionConfig(Config):
    FLASK_ENV = 'production'

我的用户模型:

from project import db, login_manager
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash

class User(db.Model, UserMixin):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String, unique=True)
    hashed_password = db.Column(db.String)

    def __init__(self, username, password):
        self.username = username
        self.hashed_password = generate_password_hash(password)

    def is_password_valid(self, password):
        return check_password_hash(self.hashed_password, password)

    def __repr__(self):
        return '<User {}>'.format(self.id)

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

我过去几天一直在做一个项目,但刚刚遇到了完全相同的错误,尽管我没有修改任何重要/相关的内容。奇怪的是,当我创建一个全新、完全独立的测试项目时,我现在也遇到了同样的问题,这让我有点困惑。 - npburns224
1
我突然遇到了同样的问题,而没有更改任何相关内容。也许是库依赖关系发生了变化? - alexander
6个回答

44

编辑

如果你遇到这个问题,将Flask-SQLAlchemy升级到>=2.5应该可以解决问题,详情请参见https://github.com/pallets/flask-sqlalchemy/issues/910#issuecomment-802098285.

不再需要将SQLAlchemy固定在~1.3。


我之前遇到了这个问题,但我认为我已经弄清楚了原因。

SQLAlchemy是作为Flask-SQLAlchemy的依赖自动安装的,其最新版本(1.4.0)引入了以下破坏性变化:

URL对象现在是一个不可变命名元组。要修改URL对象,请使用URL.set()方法生成新的URL对象。

我只需安装先前版本的SQL Alchemy (1.3.23)即可解决此问题。


4
相关的 GitHub 问题追踪修复:https://github.com/pallets/flask-sqlalchemy/issues/910 - SuperShoot
你救了我的一天。 - huynq9
将 Flask-SQLAlchemy 升级到 >= 2.5 是解决方案。并且在 config.py 文件中添加 '''SQLALCHEMY_DATABASE_URI = 'sqlite:///site2.db' #instead of os.environ.get('SQLALCHEMY_DATABASE_URI')'''。真是一场噩梦! - Corina Roca
我之前使用的是2.4.4版本,它在“主”应用程序中运行良好,但在尝试在Docker容器中执行(烟雾)测试时出现了问题,导致错误。一直在头疼到墙壁上,直到发现这个问题并尝试更新版本。真不敢相信这个错误只在Docker容器中表现出来,而且还难以调试。 - Ville Myrskyneva

10

请运行程序并确认该问题是否影响您

pip freeze

你应该发现当前的 SQLALchemy 版本是 1.4.0。我发现目前最快的解决方案是手动回滚到先前版本的 SQLAlchemy:

pip install SQLAlchemy==1.3.23

如果你刚刚还原了之前的版本并且它可以运行,那么现在是固定版本的好时机:

pip freeze > requirements.txt

4

确认npburns224 / SuperShoot的答案: 将Flask-SQLAlchemy(以及其依赖项SQLAlchemy)升级到最新版本对我很有帮助。

pip install --upgrade flask-sqlalchemy

我现在成功地运行了Flask-SQLAlchemy 2.5.1SQLAlchemy 1.4.3


1
我能够通过将我的sql-alchemy版本固定在小于1.4.0来解决这个问题。上面列出了类似的例子。以下是我解决问题的步骤,直到补丁出现。

冻结您的软件包

pip freeze > requirements.txt

在你的 requirements.txt 中更新 SQLAlchemy

SQLAlchemy<1.4.0

重新安装软件包。
pip install -r requirements.txt

如需更多关于此操作的信息,请参考pip文档:https://pip.pypa.io/en/stable/


降级SQLAlchemy到1.13.23应该没问题,升级Flask-SQLAlchemy到2.5.1也可以解决这个问题。 - Daliang LYU
是的,@DaliangLYU 是正确的,flask-sqlalchemy 有一个更新版本可以解决这个问题。请访问 https://github.com/pallets/flask-sqlalchemy/releases 获取更多信息。 - gleek

0
刚刚也遇到了同样的错误。结果发现,我安装的是错误的Flask-SQLAlchemy库。我使用conda安装它而不是pip,conda为我的操作系统和环境安装了正确的库。
conda install Flask-SQLAlchemy

-3
我通过在SQLAlchemy类中覆盖apply_driver_hacks方法来解决了这个问题。在这个新方法中,我删除了这一行:sa_url.database = os.path.join(app.root_path, sa_url.database)。我复制了方法的其余部分。
class MySQLAlchemy(SQLAlchemy):
    def apply_driver_hacks(self, app, sa_url, options):
        ...

该方法可以在这里找到。我描述的修复只应该是暂时的。问题可能会在更新版本的flask-sqlalchemy中得到解决。


抱歉,我在哪里可以找到这个方法? - Ange Uwase

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接