SQLAlchemy create_all() does not create tables

我试图集成 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

我该怎么补救?

160498 次浏览

你应该把你的模型类放在 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对象。

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

这个概念在 @ SuperShot发表的 这根线答案中得到了更好的解释

这可能不是 create_all()方法调用不适用于人们的主要原因,但对我来说,从各种教程中拼凑出来的指令让我在一个请求上下文中创建我的 db,这意味着我有这样的东西:

# 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 命令时,将使用一个新的 app 上下文,这意味着将使用一个新的 db。此外,在这个世界中,init _ db 方法中的导入模型不执行任何操作,因为可能您的模型文件已经加载(并且与一个单独的 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

我还没有深入研究 flask、 sql、或者 flask-sql,以了解这是否意味着来自多个线程的数据库请求是安全的,但是如果你正在阅读这篇文章,你可能也陷入了理解这些概念的婴儿阶段。