首页 > 解决方案 > Flask App 未在 Heroku 中创建 Postgres 数据库/表(错误:AttributeError:'NoneType' 对象没有属性'drivername')

问题描述

我已经构建了一个在本地运行的基本烧瓶 API,但是现在我已经尝试将它部署到 Heroku,当我尝试运行它时,我得到了一个广泛的错误列表。经过一番调查,我发现应用程序没有从我部署的代码中创建自己的数据库。在本地,应用程序按计划工作,并在第一次运行时使用以下代码创建了数据库:

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

在注意到我的部署中没有创建数据库之后,我尝试在 heroku 控制台中运行以下命令:

$ heroku run python
>>> from app import db
>>> db.create_all()
>>> exit()

但是,一旦我运行“从应用程序导入数据库”,我会收到以下错误消息:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/app/app.py", line 85, in <module>
    db.create_all()
  File "/app/.heroku/python/lib/python3.9/site-packages/flask_sqlalchemy/__init__.py", line 1039, in create_all
    self._execute_for_all_tables(app, bind, 'create_all')
  File "/app/.heroku/python/lib/python3.9/site-packages/flask_sqlalchemy/__init__.py", line 1031, in _execute_for_all_tables
    op(bind=self.get_engine(app, bind), **extra)
  File "/app/.heroku/python/lib/python3.9/site-packages/flask_sqlalchemy/__init__.py", line 962, in get_engine
    return connector.get_engine()
  File "/app/.heroku/python/lib/python3.9/site-packages/flask_sqlalchemy/__init__.py", line 555, in get_engine
    options = self.get_options(sa_url, echo)
  File "/app/.heroku/python/lib/python3.9/site-packages/flask_sqlalchemy/__init__.py", line 570, in get_options
    self._sa.apply_driver_hacks(self._app, sa_url, options)
  File "/app/.heroku/python/lib/python3.9/site-packages/flask_sqlalchemy/__init__.py", line 883, in apply_driver_hacks
    if sa_url.drivername.startswith('mysql'):
AttributeError: 'NoneType' object has no attribute 'drivername'

我试图确定为什么命令行和我的代码此时都不会创建数据库。

我有以下 app.py 文件运行我的整个 api

from flask import Flask, request, jsonify
from flask_restful import Api, Resource, reqparse, fields, marshal_with
from flask_sqlalchemy import SQLAlchemy
from dotenv import load_dotenv
import os
import json
from dataclasses import dataclass
from flask_cors import CORS



app = Flask(__name__)
CORS(app)
api = Api(app)

load_dotenv()

app.config['PROPAGATE_EXCEPTIONS'] = True
app.config['SQLALCHEMY_DATABASE_URI']=os.environ.get('SQL_URI')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=False

db = SQLAlchemy(app)


@dataclass
class Player(db.Model):
    id =  db.Column(db.Integer, primary_key=True)
    FIDE_Standard = db.Column(db.Integer, nullable=True)
    FIDE_Rapid = db.Column(db.Integer, nullable=True)
    FIDE_Blitz = db.Column(db.Integer, nullable=True)
    USCF_Regular = db.Column(db.Integer, nullable=True)
    USCF_Quick = db.Column(db.Integer, nullable=True)
    USCF_Blitz = db.Column(db.Integer, nullable=True)
    ChessCom_Bullet = db.Column(db.Integer, nullable=True)
    ChessCom_Blitz = db.Column(db.Integer, nullable=True)
    ChessCom_Rapid = db.Column(db.Integer, nullable=True)
    ChessCom_Daily = db.Column(db.Integer, nullable=True)
    ChessCom_Puzzle = db.Column(db.Integer, nullable=True)
    LiChess_Bullet = db.Column(db.Integer, nullable=True)
    LiChess_Blitz = db.Column(db.Integer, nullable=True)
    LiChess_Rapid = db.Column(db.Integer, nullable=True)
    LiChess_Classical = db.Column(db.Integer, nullable=True)
    LiChess_Correspondence = db.Column(db.Integer, nullable=True)
    LiChess_Puzzle = db.Column(db.Integer, nullable=True)

player_post_parser = reqparse.RequestParser()
player_post_parser.add_argument('FIDE', type=dict)
player_post_parser.add_argument('USCF', type=dict)
player_post_parser.add_argument('ChessCom', type = dict)
player_post_parser.add_argument('LiChess', type = dict)

# player_post_args= player_post_parser.parse_args()

FIDE_Parser = reqparse.RequestParser()
FIDE_Parser.add_argument('standard', type= int, location=('nested_one',))
FIDE_Parser.add_argument('rapid', type= int, location=('nested_one',))
FIDE_Parser.add_argument('blitz', type= int, location=('nested_one',))
# FIDE_args = FIDE_Parser.parse_args(req=player_post_args)

USCF_Parser = reqparse.RequestParser()
USCF_Parser.add_argument('regular', type=int, location=('nested_two',))
USCF_Parser.add_argument('quick', type=int, location=('nested_two',))
USCF_Parser.add_argument('blitz', type=int, location=('nested_two',))
# USCF_args = USCF_Parser.parse_args(req=player_post_args)

ChessCom_Parser = reqparse.RequestParser()
ChessCom_Parser.add_argument('bullet', type = int, location=('nexted_three',))
ChessCom_Parser.add_argument('blitz', type = int, location=('nexted_three',))
ChessCom_Parser.add_argument('rapid', type = int, location=('nexted_three',))
ChessCom_Parser.add_argument('daily', type = int, location=('nexted_three',))
ChessCom_Parser.add_argument('puzzle', type = int, location=('nexted_three',))
# ChessCom_args=ChessCom_Parser.parse_args(req=player_post_args)

LiChess_Parser = reqparse.RequestParser()
LiChess_Parser.add_argument('bullet', type = int, location=('nexted_four',))
LiChess_Parser.add_argument('blitz', type = int, location=('nexted_four',))
LiChess_Parser.add_argument('rapid', type = int, location=('nexted_four',))
LiChess_Parser.add_argument('classical', type = int, location=('nexted_four',))
LiChess_Parser.add_argument('correspondence', type = int, location=('nexted_four',))
LiChess_Parser.add_argument('puzzle', type = int, location=('nexted_four',))



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

   

class Players(Resource):
    def get(self):
        result =Player.query.all()
        player_list=[]
        for player in result:
            new_player={'FIDE':{
                'standard':player.FIDE_Standard,
                'rapid':player.FIDE_Rapid,
                'blitz':player.FIDE_Blitz
            },
            'USCF':{
                'regular':player.USCF_Regular,
                'quick':player.USCF_Quick,
                'blitz':player.USCF_Blitz
            },
            'ChessCom':{
                'bullet':player.ChessCom_Bullet,
                'blitz': player.ChessCom_Blitz,
                'rapid':player.ChessCom_Rapid,
                'daily':player.ChessCom_Daily,
                'puzzle':player.ChessCom_Puzzle
            },
            'LiChess':{
                'bullet':player.LiChess_Bullet, 
                'blitz':player.LiChess_Blitz, 
                'rapid':player.LiChess_Rapid, 
                'classical':player.LiChess_Classical, 
                'correspondence':player.LiChess_Correspondence, 
                'puzzle':player.LiChess_Puzzle
            }
            }
            player_list.append(new_player)
            
        return jsonify(player_list)
    def post(self):
        player_post_args = player_post_parser.parse_args()
        FIDE_args=FIDE_Parser.parse_args(req=player_post_args)
        USCF_args=USCF_Parser.parse_args(req=player_post_args)
        ChessCom_args=ChessCom_Parser.parse_args(req=player_post_args)
        LiChess_args=LiChess_Parser.parse_args(req=player_post_args)


        player= Player(
        FIDE_Standard= player_post_args['FIDE']['standard'],
        FIDE_Rapid=player_post_args['FIDE']['rapid'],
        FIDE_Blitz=player_post_args['FIDE']['blitz'],
        USCF_Regular=player_post_args['USCF']['regular'],
        USCF_Quick=player_post_args['USCF']['quick'],
        USCF_Blitz=player_post_args['USCF']['blitz'],
        ChessCom_Bullet=player_post_args['ChessCom']['bullet'],
        ChessCom_Blitz=player_post_args['ChessCom']['blitz'],
        ChessCom_Rapid=player_post_args['ChessCom']['rapid'],
        ChessCom_Daily=player_post_args['ChessCom']['daily'],
        ChessCom_Puzzle=player_post_args['ChessCom']['puzzle'],
        LiChess_Bullet=player_post_args['LiChess']['bullet'],
        LiChess_Blitz=player_post_args['LiChess']['blitz'],
        LiChess_Rapid=player_post_args['LiChess']['rapid'],
        LiChess_Classical=player_post_args['LiChess']['classical'],
        LiChess_Correspondence=player_post_args['LiChess']['correspondence'],
        LiChess_Puzzle=player_post_args['LiChess']['puzzle'],
        )
       
        db.session.add(player)
        db.session.commit()
        # return player

api.add_resource(Players, '/players')

if __name__ =="__main__":
    app.run(debug=True)

标签: pythonflaskheroku

解决方案


事实证明,在我的 heroku 设置和 app.py 文件中,我的 SQL DB url 的 .env 值有一个不同的名称。


推荐阅读