当我使用 flask run 运行 Flask 服务器时,我在索引页中收到错误 404。
`${id}`
<块引用>
未找到
在服务器上找不到请求的 URL。如果您输入了网址 请手动检查您的拼写,然后重试。
* Serving Flask app "sf.py"
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [18/Feb/2021 10:25:56] "GET / HTTP/1.1" 404 -
.
├── app
│ ├── models.py
│ ├── routes.py
│ └── __init__.py
├── clients
│ └── client.py
├── migrations
├── tests
│ ├── conftest.py
│ ├── test_models.py
│ ├── test_client.py
│ └── __init__.py
├── publisher.py
├── manage.py
├── run_client.py
├── requirements.txt
└── sf.py
/sf.py
from app import create_app
create_app()
/app/__init__.py
from flask import Flask
from . models import db
POSTGRES = {
'user': 'sf',
'pw': 'sf',
'db': 'sf',
'host': 'localhost',
'port': '5432',
}
def create_app():
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s' % POSTGRES
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
return app
from app import routes
/app/routes.py
我需要使用 from app import create_app
from app.models import Area, Sensor, Monitoring
from flask import request, jsonify
from flask.views import MethodView
app = create_app()
@app.route('/')
def hello_world():
return 'Hello, World!'
...
,因为我需要 create_app()
使用该应用程序。
/clients/client.py
/clients/client.py
但是这样我得到了 404 错误。而且我不确定我是否正确使用了该应用程序。将应用程序和数据库会话分开会很好,可以在不关心应用程序配置的情况下测试模型和客户端(可能我需要为测试创建单独的配置?)。我错过了什么?
答案 0 :(得分:3)
您正在创建 Flask()
对象的三个实例。一个在 sf.py
中创建,其他在 routes.py
和 client.py
中创建。第一个用于为站点提供服务,因此没有您的路由,因为该路由已注册到在 routes.py
中创建的实例。 client.py
中的第三个实例是独立的,不会进一步改变,所以这里不是问题;更多内容见下文。
不要创建多个副本,至少不要和更改一个上的注册并期望那些在另一个上可用。相反,使用 blueprints 注册您的视图,然后使用 Flask()
函数中的 create_app()
对象注册蓝图。这样,您可以将路线注册与创建 Flask()
对象分离,并且仍然可以集中注册您的路线。
在您的 routes.py
中,使用:
from app.models import Area, Sensor, Monitoring
from flask import Blueprint, request, jsonify
from flask.views import MethodView
bp = Blueprint('main', __name__)
@bp.route('/')
def hello_world():
return 'Hello, World!'
# ...
然后在 create_app()
中导入该蓝图:
def create_app():
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s' % POSTGRES
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
from . import routes
app.register_blueprint(routes.bp)
return app
您想在 create_app()
中进行导入的原因是,在大多数 Flask 应用程序中,您还将使用一个或多个通常在 create_app()
之外创建的 Flask 扩展,以便您的视图可以导入他们。如果您的 routes
模块在顶级导入到 routes
,如果您尝试在 app.py
模块中导入这些对象之一,您将获得循环导入。
通过此更改(使用蓝图),您可以避免创建单独的 Flask()
实例,其中的注册用于服务您的站点的主实例不会看到。如果需要(例如,如果您需要使用 client.py
生成网址),即使您的 url_for()
进程现在也可以访问这些路由。
以下是我最近为客户构建的生产中 Flask 项目的示例,app.py
模块部分包含以下代码:
from flask import Flask
from flask_babel import Babel
from flask_marshmallow import Marshmallow
from flask_migrate import Migrate
from flask_security import Security, SQLAlchemyUserDatastore
from flask_sqlalchemy import SQLAlchemy
babel = Babel()
db = SQLAlchemy()
ma = Marshmallow()
migrate = Migrate()
security = Security()
_app_init_hooks = []
app_init_hook = _app_init_hooks.append
def create_app():
app = Flask(__name__)
for f in _app_init_hooks:
f(app)
return app
@app_init_hook
def _configure(app):
"""Load Flask configurations"""
app.config.from_object(f"{__package__}.config")
# optional local overrides
app.config.from_pyfile("settings.cfg", silent=True)
app.config.from_envvar("PROJECT_NAME_SETTINGS", silent=True)
@app_init_hook
def _init_extensions(app):
"""Initialise Flask extensions"""
if app.env != "production":
# Only load and enable when in debug mode
from flask_debugtoolbar import DebugToolbarExtension
DebugToolbarExtension(app)
# Python-level i18n
babel.init_app(app)
# Database management (models, migrations, users)
from .models import Role, User
db.init_app(app)
migrate.init_app(app, db)
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security.init_app(app, user_datastore)
# Marshmallow integration (must run after db.init_app())
ma.init_app(app)
@app_init_hook
def _setup_blueprints(app):
"""Import and initialise blueprints"""
from . import users
from .sections import BLUEPRINTS
for blueprint in (*BLUEPRINTS, users.bp):
app.register_blueprint(blueprint)
return app
我已将各种组件分解为单独的功能以简化可读性和可维护性,有单独的蓝图用于不同的网站功能(这会推动 UI 中的一些自动化)。
在模块的顶部是几个 Flask 扩展,各种路由和其他模块需要访问这些扩展,而不必担心循环导入,因此蓝图在调用的 _setup_blueprints()
钩子函数内部单独导入create_app()
。
您在 create_app()
中使用 client.py
应该没问题,因为它不会向您希望在其他地方访问的 Flask()
实例添加任何新配置,并且大概client.py
在 Flask 网络服务器进程之外使用。但我个人只会将 create_app()
的结果设为您的 Client
实例的实例属性。您不需要全局变量,您只需要它在调用 add_reading()
时轻松访问数据库会话:
class CustomClient(Client):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs):
# Create a Flask context so we can access the SQLAlchemy session
self._app = create_app()
def add_reading(self, reading):
with self._app.app_context():
db.session.add(reading)
db.session.commit()
# ...
如果 add_reading()
被频繁调用,您可以考虑将 app
设为 CustomClient()
的实例属性: