SQLAlchemy create_all() 不创建表

问题描述 投票:0回答:4

我正在尝试集成 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', '[email protected]')
guest = User('guest', '[email protected]')
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

我该如何解决这个问题?

python postgresql sqlalchemy flask-sqlalchemy
4个回答
208
投票

您应该将模型类放在

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', '[email protected]'))
    db.session.add(User('guest', '[email protected]'))
    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', '[email protected]'))
    db.session.add(User('guest', '[email protected]'))
    db.session.commit()
    
    users = User.query.all()
    print(users)

重要提示: 在初始化

db
对象后导入模型非常重要,因为在
models.py
中,您还需要从此模块导入
db
对象。


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发布的这个帖子

的答案得到了更好的解释

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()

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

运行 cli 命令时,将使用新的应用程序上下文,这意味着使用新的数据库。此外,在这个世界上, 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 进行足够深入的研究,无法理解这是否意味着从多个线程向数据库发出的请求是安全的,但如果您正在阅读本文,您可能还停留在理解的婴儿阶段这些概念也是如此。


0
投票

我在 db.py 文件中使用了上述信息,如下所示。我发现创建单独的 app.py、db.py 和 server.py 文件以避免循环依赖很重要。

from flask_sqlalchemy import SQLAlchemy
from app import app
from werkzeug.security import generate_password_hash

db = SQLAlchemy(app)

#
# The models need to be imported after the db is initialized.
#
from models.user import User
from models.video_attributes import VideoAttributes
from models.model_development import ModelDevelopment

with app.app_context() as ctx:
    ctx.push()
    db.create_all()

    # Check for existing users
    if User.query.count() == 0:
        # Create first user as admin
        db.session.add(User(login="admin", password=generate_password_hash("admin")))
        db.session.commit()
© www.soinside.com 2019 - 2024. All rights reserved.