SQLAlchemy的create_all()方法无法创建表格

129

我正在尝试集成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() - Syed Habib M
1
请打印整个回溯信息。 - Kobi K
2
__tablename__ = "users" 添加到您的模型中,然后再试一次。 - ajknzhol
1
这个问题已经有点过时了,但我在尝试解决同样的问题时遇到了它,并想补充一下:覆盖__init__而不调用super()可能会导致OP遇到的问题。在OP的情况下,根本不需要覆盖__init__。OP的__iniit__函数并没有添加任何超类没有做的事情。 - infosmith
3个回答

206

你应该在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

with app.app_context():
    db.create_all()

    db.session.add(User('admin', 'admin@example.com'))
    db.session.add(User('guest', 'guest@example.com'))
    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

with app.app_context():
    db.create_all()

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

重要提示:在初始化db对象之后导入您的模型非常重要,因为在models.py中,您还需要从该模块导入db对象。


1
很棒的答案。实现的修复遵循了Flask应用程序的逻辑操作顺序(OOP)。OOP表明必须首先定义db对象以及任何表/自定义,然后才能调用Python服务器来创建数据库及其依赖表,以供“暂存区”使用,然后再提交。在原始帖子中,“db.create_all”命令太早出现在序列中,因此出现了找不到关系“user”的错误消息。 - Paul Sochacki
12
我是唯一一个想知道 db.create_all 如何知道已定义了用户的人吗? - masonCherry
3
它查找所有继承db.Model的类。 - Shishir Pandey
4
有没有使用工厂方法来完成这个操作的方式?应用程序和数据库变量是有范围限制的,因此不能在单独的模型文件中引用它们吗? - 2c2c

4

这可能不是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()

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

当运行命令行命令时,会使用一个新的应用上下文,这意味着会使用一个新的数据库。此外,在这个世界里,init_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

我还没有深入了解 Flask、SQLAlchemy 或 Flask-SQLAlchemy,以确定从多个线程对数据库的请求是否安全,但如果你正在阅读这篇文章,那么你很可能还处于初步了解这些概念的阶段。


4

如果有人在使用每个模型专用文件来创建表格时遇到问题,请注意不要从声明该函数的文件不同的文件中运行“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”函数时要小心。

这个概念通过此线程的答案更好地解释,该线程由@SuperShoot发布。


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