Flask:当我尝试访问索引时得到错误404



当我运行Flask ServerFlask run,我得到错误404在索引页。

* 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 -
未找到

请求的URL在服务器上找不到。如果您输入URL请手动检查拼写,然后再试一次。

  • 项目结构
.
├── 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
from paho.mqtt.client import Client
import json
from app import create_app
from app.models import db
from app.models import Monitoring

app = create_app()

class CustomClient(Client):
def add_reading(self, reading):
with app.app_context():
db.session.add(reading)
db.session.commit()
def on_connect(self, client, userdata, flags, rc):
print(
"Connected:", 
str(client._host) + ":" + str(client._port)
)
def on_subscribe(self, mqttc, obj, mid, granted_qos):
print(
"Subscribed:", 
str(mid), str(granted_qos)
)
def on_message(self, client, userdata, message):
msg = message.payload.decode()
print(message.topic, msg)
data = json.loads(msg)
reading = Monitoring(**data)
self.add_reading(reading)
def run(self):
self.connect("localhost", 1883, 60)
self.subscribe("Main/#", 0)
self.loop_forever()

但是这样我得到了404错误。我不确定我是否正确使用了这个应用。这将是很好的有一个应用程序和数据库会话分开,测试模型和客户端不关心应用程序配置(可能我需要创建一个单独的配置测试?)。我错过了什么?

您正在创建三个Flask()对象的实例。一个在sf.py中创建,另一个在routes.pyclient.py中创建。第一个用于服务站点,因此没有您的路由,因为路由注册在routes.py中创建的实例中。第三个实例,在client.py是独立的,没有进一步改变,所以这里不是一个问题;

不要创建多个副本,至少不要更改一个副本上的注册,并期望这些副本在另一个副本上可用。相反,使用蓝图来注册您的视图,然后在create_app()函数中用Flask()对象注册蓝图。这样,你就可以将注册路由与创建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应用程序中,你也会使用一个或多个Flask扩展,这些扩展通常是在create_app()之外创建的,所以你的视图可以导入它们。如果您的routes模块在顶层被导入app.py,那么如果您试图在routes模块中导入其中一个对象,您将得到一个循环导入。

通过此更改(使用蓝图),您可以避免创建一个单独的Flask()实例,其中包含用于为站点提供服务的主实例无法看到的注册。如果有需要,甚至你的client.py进程现在也可以访问这些路由(例如,如果你需要用url_for()生成url)。

以下是我最近为客户端构建的一个生产中的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扩展,各种路由和其他模块都需要访问它们,而不必担心循环导入,因此蓝图在create_app()调用的_setup_blueprints()钩子函数中被单独导入。

您在client.py中使用create_app()应该是好的,因为它不会向Flask()实例添加任何您想要访问其他地方的新配置,并且可能client.py在Flask web服务器进程之外使用。但我个人认为,只是使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()的实例属性:

最新更新