【问题标题】:SQLAlchemy create_all() does not create tablesSQLAlchemy create_all() 不创建表
【发布时间】:2014-01-11 17:10:21
【问题描述】:

我正在尝试集成 PostgreSQL 和 SQLAlchemy,但 SQLAlchemy.create_all() 没有从我的模型中创建任何表。

我的代码:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://login:pass@localhost/flask_app'
db = SQLAlchemy(app)
db.create_all()
db.session.commit()

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)

    def __init__(self, username, email):
        self.username = username
        self.email = email

    def __repr__(self):
        return '<User %r>' % self.username

admin = User('admin', 'admin@example.com')
guest = User('guest', 'guest@example.com')
db.session.add(admin)
db.session.add(guest)
db.session.commit()
users = User.query.all()
print users        

但我收到此错误:sqlalchemy.exc.ProgrammingError: (ProgrammingError) relation "user" does not exist

我该如何解决这个问题?

【问题讨论】:

  • 你用shell检查过from yourapplication import db db.create_all()吗?
  • 请打印整个引用
  • __tablename__ = "users" 添加到您的模型并重试。
  • 这个问题已经过时了,但我在尝试解决同样的问题时遇到了它,并想补充一点,在不调用 super() 的情况下覆盖 init 可能会导致问题OP正在经历。在 OP 的情况下,根本不需要覆盖 init 。 OP 的 init 函数不会添加超类尚未执行的任何操作。

标签: python postgresql sqlalchemy


【解决方案1】:

你应该把你的模型类放在create_all()调用之前,像这样:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://login:pass@localhost/flask_app'
db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)

    def __init__(self, username, email):
        self.username = username
        self.email = email

    def __repr__(self):
        return '<User %r>' % self.username

db.create_all()
db.session.commit()

admin = User('admin', 'admin@example.com')
guest = User('guest', 'guest@example.com')
db.session.add(admin)
db.session.add(guest)
db.session.commit()
users = User.query.all()
print users

如果您的模型在单独的模块中声明,请在调用 create_all() 之前导入它们。

假设User 模型在一个名为models.py 的文件中,

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://login:pass@localhost/flask_app'
db = SQLAlchemy(app)

# See important note below
from models import User

db.create_all()
db.session.commit()

admin = User('admin', 'admin@example.com')
guest = User('guest', 'guest@example.com')
db.session.add(admin)
db.session.add(guest)
db.session.commit()
users = User.query.all()
print users

重要提示:在初始化db 对象后导入模型很重要,因为在models.py 中_您还需要从此模块导入db 对象。

【讨论】:

  • 精彩的答案。实施的修复遵循 Flask 应用程序的逻辑操作顺序 (OOP)。 OOP 指示必须首先定义 db 对象以及任何表/自定义,然后才能调用 Python 服务器以在提交之前为“暂存区”创建数据库及其依赖表。在原始帖子中,db.create_all 命令在序列中太早了,因此错误消息提示找不到关系“用户”。
  • 只有我一个人想知道db.create_all 是如何知道用户已被定义的吗?
  • 查找所有继承db.Model的类。
  • 这应该是我在 Stack Overflow 上看到的最明确的答案之一!!!
  • 有没有办法使用工厂方法来做到这一点? app 和 db 变量是作用域的,因此不能在单独的模型文件中引用?
【解决方案2】:

如果有人在使用每个模型专用的文件创建表时遇到问题,请注意从与声明该函数的文件不同的文件中运行“create_all”函数。 所以,如果文件系统是这样的:

Root  
--app.py     <-- file from which app will be run
--models
----user.py      <-- file with "User" model
----order.py    <-- file with "Order" model
----database.py <-- file with database and "create_all" function declaration

小心从 app.py 调用“create_all”函数。

@SuperShootthis thread 的回答更好地解释了这个概念

【讨论】:

    【解决方案3】:

    这可能不是 create_all() 方法调用对人们不起作用的主要原因,但对我来说,来自各种教程的拼凑说明让我在请求上下文中创建我的数据库,这意味着我有类似的东西:

    # lib/db.py
    from flask import g, current_app
    from flask_sqlalchemy import SQLAlchemy
    
    def get_db():
      if 'db' not in g:
        g.db = SQLAlchemy(current_app)
      return g.db
    

    我还有一个单独的 cli 命令也可以执行 create_all:

    # tasks/db.py
    from lib.db import get_db
    
    @current_app.cli.command('init-db')
    def init_db():
      db = get_db()
      db.create_all()
    

    我也在使用应用程序工厂。

    运行 cli 命令时,会使用一个新的应用上下文,这意味着使用了一个新的数据库。此外,在这个世界上, init_db 方法中的导入模型不会做任何事情,因为可能是您的模型文件已经加载(并与单独的数据库相关联)。

    我解决的办法是确保 db 是一个单一的全局引用:

    # lib/db.py
    from flask import g, current_app
    from flask_sqlalchemy import SQLAlchemy
    
    db = None
    def get_db():
      global db
      if not db:
        db = SQLAlchemy(current_app)
      return db
    

    我对烧瓶、sqlalchemy 或烧瓶-sqlalchemy 的研究还不够深入,无法了解这是否意味着从多个线程对数据库的请求是安全的,但如果您正在阅读本文,您可能会陷入婴儿阶段理解这些概念。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-29
      • 1970-01-01
      • 2011-03-11
      • 2015-06-02
      • 1970-01-01
      • 2022-01-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多