【问题标题】:Table 'roles_users' is already defined for this MetaData instance已经为此 MetaData 实例定义了表 'roles_users'
【发布时间】:2016-10-20 21:32:00
【问题描述】:

我正在尝试在我的视图中获取 current_user 信息,我包含来自users.models import *

然后在我的代码中返回 current_user;

@app.route('/panel')
@login_required
def access_panel():
    return current_user.email;

一旦我运行我的服务器,它会说:

Traceback (most recent call last):
  File "manage.py", line 6, in <module>
    from nadel import app
  File "/Users/tbd/Desktop/Projects/nadel/__init__.py", line 27, in <module>
    from users import views
  File "/Users/tbd/Desktop/Projects/nadel/users/views.py", line 5, in <module>
    from users.models import *
  File "/Users/tbd/Desktop/Projects/nadel/users/models.py", line 8, in <module>
    db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
  File "/Library/Python/2.7/site-packages/flask_sqlalchemy/__init__.py", line 67, in _make_table
    return sqlalchemy.Table(*args, **kwargs)
  File "/Library/Python/2.7/site-packages/sqlalchemy/sql/schema.py", line 398, in __new__
    "existing Table object." % key)
sqlalchemy.exc.InvalidRequestError: Table 'roles_users' is already defined for this MetaData instance.  Specify 'extend_existing=True' to redefine options and columns on an existing Table object.

在我的模型中,我有:

from nadel import db
from flask.ext.security import UserMixin, RoleMixin

# Define models
roles_users = db.Table('roles_users',
        db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
        db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))

class Role(db.Model, RoleMixin):
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(80), unique=True)
    description = db.Column(db.String(255))

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(255), unique=True)
    name = db.Column(db.String(255))
    password = db.Column(db.String(255))
    active = db.Column(db.Boolean())
    #confirmed_at = db.Column(db.DateTime())
    last_login_at = db.Column(db.DateTime())
    current_login_at = db.Column(db.DateTime())
    last_login_ip = db.Column(db.String(32))
    current_login_ip = db.Column(db.String(32))
    login_count = db.Column(db.Integer)

    roles = db.relationship('Role', secondary=roles_users,
                            backref=db.backref('users', lazy='dynamic'))

我不明白为什么我会收到此错误以及如何解决它。

【问题讨论】:

  • 我在使用 py3 的测试环境下运行 doctests 时遇到了同样的问题,当 pytest 开始收集文件时会出现同样的错误。我发现这个错误可能与 py3 环境有关,在当前版本的 flask-sqlalchemy 库中引入了最新更改。我在 py2.7 中运行时没有任何问题,但这不是我的选择,所以我转向了完全解决问题的普通 SQLAlchemy 库。
  • 该表已经存在于您的数据库中,因此您可以稍微更改设置或仅捕获InvalidRequestError 和除roles_users = db.metadata.tables["roles_users"] 之外的roles_users = db.metadata.tables["roles_users"],或者仅在表调用中设置useexisting=True /跨度>
  • @PadraicCunningham ,你能详细说明你的方法吗?我面临同样的问题,但仍然无法解决。

标签: python sqlalchemy


【解决方案1】:

尝试添加:

__table_args__ = {'extend_existing': True}

就在__tablename__下方

参考:https://docs.sqlalchemy.org/en/13/orm/extensions/declarative/table_config.html?highlight=table_args

【讨论】:

  • 这会修改数据库中的表还是只修改表对象?
  • 这个解决方案有效,但我有兴趣了解它的实际作用。
  • 此解决方案可能有效,但如果有效,它很有可能会掩盖其他问题 - 我建议先探索其他选项,然后再将其作为创可贴贴在桌子上。跨度>
  • 这并不能解决问题。它只会使错误消失。此设置:表示现有 Table 对象中存在的 Column 对象应替换为从自动加载过程中检索到的同名列。
【解决方案2】:

我遇到了类似的错误。我的问题是使用相对导入从两个不同的文件中导入继承 db.Model 的类。 Flask-SQLAlchemy 将两个导入映射为两个不同的表定义,并尝试创建两个表。我通过在两个文件中使用绝对导入路径解决了这个问题。

【讨论】:

  • 遇到了同样的问题,我是导入db.Model一次相对,一次绝对。
  • 是的,这发生在我身上,因为我正在移动一些代码...... IDE 很有帮助地将一个导入放在 src.db.models,另一个放在 src.db.models(所以我的模型是分别导入两次)
  • 也为我工作
  • 这个答案也是我的问题的根源(在测试中相同模型的导入路径不同)。添加 __table_args__ = {'extend_existing': True} 可以解决 ORM 级别的问题,但不能解决代码中的问题。我认为应该是最后的努力。
【解决方案3】:

当我通过复制粘贴以前的课程创建新课程时出现此错误。原来我忘记更改__tablename__,所以我有两个具有相同__tablename__ 属性的类。这导致了错误,更改属性解决了它。

【讨论】:

    【解决方案4】:

    这取决于您想做什么,您是否尝试:

    1. 删除旧类并用新的类映射替换它?或者,
    2. 保留旧课程并重新启动您的应用?

    在使用上面的示例的第一种情况下,在定义类之前尝试运行以下行:

    db.metadata.clear()
    

    原因是第一次通过定义python类来声明SQLAlchemy Mapping,类的定义保存到元数据对象中,以防止多个定义映射到同一张表引起冲突。

    当您调用clear() 方法时,您会清除由元数据对象保存在内存中的所有表定义,这允许您再次声明它们。

    在第二种情况下,您只是重新启动应用程序 我会使用reflect method 编写一个测试以查看该表是否已存在:

    db.metadata.reflect(engine=engine)
    

    其中引擎是您使用create_engine() 创建的数据库连接,并查看您的表是否已经存在,如果表未定义,则仅定义类。

    【讨论】:

    【解决方案5】:

    迟到了一年,但如果有人在给定的答案中找不到解决方案,这可能会解决问题 -

    我的类继承自 db.Model(flask_sqlalchemy)也有同样的问题。

    我的代码看起来像这样 -

    class MasterDB(db.Model):
        __tablename__ = 'masterdb'
        __table_args__ = {'schema': 'schema_any'}
        ...
        ...
    

    通过在类变量列表中将 abstract 属性指定为 True 来解决它。 像这样将它添加到类变量列表中,它应该可以工作 -

    class MasterDB(db.Model):
        __tablename__ = 'masterdb'
        __table_args__ = {'schema': 'schema_any'}
        __abstract__ = True
    

    【讨论】:

      【解决方案6】:

      我的名字是雅各布。我也有同样的情况。

      问题是这样的:当您在同一代码中导入父表和子表时会发生这种情况。然后导入 CHILD 表,CHILD 表将父表的结构也带入元数据。所以你不需要再次导入 PARENT 表。

      解决方案是这样的:您需要重新排列代码中导入 ORM 结构的顺序。顺序基于父+子关系。

      示例:以下产生错误:

      import CHILD_ORM
      import PARENT_ORM   
      

      重新排列顺序如下,防止出错:

      import PARENT_ORM   
      import CHILD_ORM
      

      【讨论】:

      • 这是解决我的问题的唯一答案:我正在尝试使用 Alembic 的 GINO,并且需要以 migrations/env.py 中的正确顺序手动导入我的所有模型才能使其正常工作。谢谢!
      【解决方案7】:

      TL;DR

      • 如果您在尝试将烧瓶蓝图注册到应用程序时遇到此错误,请检查导入模型的所有蓝图中的模型导入路径是否一致

      例如

      • 蓝图1:from A.B.C import Model A
      • 蓝图 2:from .B.C import Model A(这会引发错误,导入路径应该在所有导入相同模型的蓝图中保持一致。所以应该是 from A.B.C import Model A

      我没有挖掘这个问题来找出原因,但我猜 SQLAlchemy 使用其导入的命名空间管理模型,并在定义不同的命名空间但模型相同时引发错误。

      【讨论】:

        【解决方案8】:

        在开发模式下运行烧瓶应用程序时出现此错误:

        FLASK_ENV=development flask run
        

        flask 的动态重新加载功能显然会像您预期的那样重新加载元数据实例。按照“Spcogg the second”的建议重新启动应用程序为我解决了这个问题!

        【讨论】:

          【解决方案9】:

          很可能是导入中的错误。

          只是roles_users模型在你的一个组件中被多次导入。

          如果您导入了多个组件,其中已经导入了所需模型,则可能会发生这种情况

          例子:

          from schemas.user import UserSchema # have `from models.user import User` inside
          from blocs.users import UsersBLOC # have `from models.user import User` inside
          

          【讨论】:

            【解决方案10】:

            我在导入和明确定义外键关系中的模型时遇到了这个问题(如官方文档的examples

            不好:

            ForeignKey(User.id)

            好吧(不是导入模型):

            ForeignKey("user.id")

            【讨论】:

              【解决方案11】:

              我不是百分百确定,但是这个问题可能是由于同一个表从同一个模块创建了两次。在我的情况下,我意识到我正在从两个不同的位置导入同一个模块并且module.__init__ 会自动执行,它会导入model.py 两次。因此导致元数据冲突,我猜元数据/命名空间是完全相同的。我阅读了其他答案,但没有一个明确解释我们在这里有哪些选择。

              就我查看源代码而言,我们有两个选择:

              1. __table_args__ = {'extend_existing': True}
              2. __table_args__ = {'keep_existing': True}

              顾名思义,第一个允许您扩展表,但根据具体情况,这不是您的首选。我不确定这是否会产生任何性能开销,但也有这种可能性。

              第二个选项只是保持表格原样而不修改它。最后,第二个选项是我的首选,我认为这只是一个简单的检查表是否存在。

              【讨论】:

                【解决方案12】:

                我在使用 jupyter notebook 时看到了同样的错误。我正在从存储在磁盘上的库中导入 sqlalchemy 表类,并且定义中存在错误。修复错误后,我重新运行导入并看到此错误。只需重新启动 jupyter 内核,然后重新运行导入即可解决问题。

                【讨论】:

                  【解决方案13】:

                  只需为角色用户添加extend_existing=True,如下所示

                  # Define models
                  roles_users = db.Table('roles_users',
                      db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
                      db.Column('role_id', db.Integer(), db.ForeignKey('role.id')),
                      extend_existing=True)
                  

                  【讨论】:

                    猜你喜欢
                    • 2015-12-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2015-11-21
                    • 1970-01-01
                    • 2014-11-01
                    • 2022-11-21
                    • 2016-03-03
                    相关资源
                    最近更新 更多