我的烧瓶应用程序工厂返回未找到的URL

时间:2019-06-06 01:06:29

标签: python flask

我的烧瓶应用程序基于Miguel Grinberg的大型教程XIV,其中包含一些其他内容,并且一切正常,可以从本地主机上的浏览器访问:5000。我决定根据Grinberg的XV教程BUT切换到应用程序工厂方法,但没有蓝图。现在,当我输入localhost:5000时,找不到URL。我猜我的route.py由于某种原因未被提取。

我已经彻底研究了格林伯格的XV教程和相关代码,并调整了所有没有蓝图的内容。这些是我目前基于我的应用程序探索的链接:-

https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xv-a-better-application-structure

http://flask.pocoo.org/docs/1.0/tutorial/factory/

戴夫·史密斯(Dave W Smith)在Configure Python Flask App to use "create_app" factory and use database in model class中的回答

和其他人。

从我阅读的内容来看,实现应用程序工厂应该非常简单。这些示例起作用。

烧瓶服务器一如既往地从venv命令提示符处启动。

这是我的目录结构。

myapp
    app.py
    config.py
    ...
    /app
        __init__.py
        routes.py
        models.py
        forms.py
        ...

为了清楚起见,这里的代码略有简化。

# app.py
#=============================================
from app import create_app, db
from app.models import User, Post

app = create_app()

@app.shell_context_processor
def make_shell_context():
    return {'db': db, 'User': User, 'Post' :Post}

# __init__.py
#=============================================
...
import os
from flask import Flask, request, current_app
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
...
from config import Config

db = SQLAlchemy()
migrate = Migrate()
...

def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)

    db.init_app(app)
    migrate.init_app(app, db)
    ...

    # logging, email servers, etc configured

    return app

from app import models

# routes.py
#=============================================
from datetime import datetime
from flask import render_template, flash, redirect, url_for, request, g, \
    jsonify, current_app
...
from app import app, db
from app.forms import LoginForm, RegistrationForm, EditProfileForm, 
     PostForm,ResetPassword,RequestForm, ResetPasswordForm
from app.models import User, Post
...

@app.route('/', methods=['GET', 'POST'])
@app.route('/index', methods=['GET', 'POST'])
@login_required
def index():
    form = PostForm()
    if form.validate_on_submit():
        ...
    page = request.args.get('page', 1, type=int)
    ...
    return render_template('index.html', title=_('Home'), form=form,
                           posts=posts.items, next_url=next_url,
                           prev_url=prev_url)

@app.route ....


# models.py
#=============================================
from datetime import datetime
from hashlib import md5
from time import time
from flask import current_app
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
import jwt
from app import db, login

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), index=True, unique=True)
    ...

这可能无关紧要,但这是我尝试过的一件事。请注意,在routes.py中,我拥有from app import app, db,如果删除app并添加from flask import current_app,则@app装饰器将显示为未定义。

另一点,因为它与路线有关。如果将__init__.py的最后一行更改为from app import routes, models,则会收到其他错误。

flask.cli.NoAppException
flask.cli.NoAppException: While importing "metapplica", an ImportError was raised:

Traceback (most recent call last):
  File "c:\users\markko~1\dropbox\python\projects\metapp~1\venv\lib\site-packages\flask\cli.py", line 236, in locate_app
    __import__(module_name)
  File "C:\Users\Mark Kortink\Dropbox\Python\projects\metapplica\metapplica.py", line 1, in <module>
    from app import create_app, db, cli
  File "C:\Users\Mark Kortink\Dropbox\Python\projects\metapplica\app\__init__.py", line 75, in <module>
    from app import routes, models
  File "C:\Users\Mark Kortink\Dropbox\Python\projects\metapplica\app\routes.py", line 8, in <module>
    from app import app, db
ImportError: cannot import name 'app' from 'app' (C:\Users\Mark Kortink\Dropbox\Python\projects\metapplica\app\__init__.py)

正是这个错误导致我尝试进行上述current_app更改。

我这样启动应用程序。

cd C:\Users\...\myapp
venv\Scripts\activate 
set FLASK_APP=app.py
set FLASK_DEBUG=1
flask run

我知道问题可能真的很基本,但是没有人能看到上面的代码为什么会给出未找到的URL或找不到路由吗?

===下一阶段================ 遵循@silver的建议,我的新名字如下:-

myapp
    runapp.py
    ...
    /mapp
        __init__.py
        ...

我遍历了所有代码,并将from app[.xxx] import yyy更改为from myapp[.xxx] import yyy。这清除了我引用app时解决的一些新错误,而我通过替换current_app进行了修复。 我的新错误是

RuntimeError
RuntimeError: Working outside of application context.

This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context().  See the
documentation for more information.

Traceback (most recent call last)
File "C:\Users\Mark Kortink\Dropbox\Python\projects\myapp\runapp.py", line 1, in <module>
from mapp import create_app, db, cli
File "C:\Users\Mark Kortink\Dropbox\Python\projects\myapp\mapp\__init__.py", line 75, in <module>
from mapp import routes, models
File "C:\Users\Mark Kortink\Dropbox\Python\projects\myapp\mapp\routes.py", line 16, in <module>
@current_app.before_request

2 个答案:

答案 0 :(得分:0)

如果无法自己运行,则很难确定。 但是我认为这是问题的症结所在:

  

这可能无关紧要,但这是我尝试过的一件事。请注意,在routes.py中,我从应用程序导入应用程序db获得,如果我删除了应用程序并从烧瓶导入current_app添加,则@app装饰器显示为未定义。

如果要将任何内容注册到实际运行的应用程序,则必须通过from flask import current_app。 Flask应用程序工厂就是这样-您只能访问实际上在两个地方运行的应用程序的名称:

  1. 在工厂函数本身中:create_app,然后返回app对象,然后
  2. 通过from flask import current_app

由于您说应用程序已启动,因此Python似乎能够成功导入app中的名称routes.pyfrom app import app可以解析的唯一位置是来自app.py包顶层的myapp文件。这意味着每次初始化routes.py时,它都会调用create_app函数,并获得一个新的app对象。因此可以理解,Flask服务的顶级app对象与为其注册了路由的对象不同。 我建议重命名您的文件,以便除create_app返回的对象外,其他都没有名称“ app”。

然后,在routes.py中尝试:

from datetime import datetime
from flask import render_template, flash, redirect, url_for, request, g, \
    jsonify
from flask import current_app as app_ref
...
from app_internals import db  # assuming you've renamed the app package
from app_internals.forms import LoginForm, RegistrationForm, EditProfileForm, 
     PostForm,ResetPassword,RequestForm, ResetPasswordForm
from app_internals.models import User, Post
...

current_app =  app_ref._get_current_object()

@current_app.route('/', methods=['GET', 'POST'])
@current_app.route('/index', methods=['GET', 'POST'])
@login_required
def index():
    form = PostForm()
    if form.validate_on_submit():
        ...
    page = request.args.get('page', 1, type=int)
    ...
    return render_template('index.html', title=_('Home'), form=form,
                           posts=posts.items, next_url=next_url,
                           prev_url=prev_url)

@current_app.route ....

答案 1 :(得分:0)

我刚刚在Miguel Grinberg的教程中也遇到了这个问题。这是一个非常棒的教程,直到随后的部分内容匆匆忙忙为止。

无论如何。 您需要传递上下文。 在工厂功能中,您需要做的。

    def create_app(config_class=Config):
        app = Flask(__name__)
        with app.app_context():
            from app import routes

然后像上面发布的人一样。 对于route.py,将所有@app更改为@current_app

    from flask import current_app
    @current_app.route('/')
    @current_app.route('/index', methods=['GET', 'POST'])
    @login_required
    def index():

这对我有用。