我有一个 Flask 应用程序,我正在尝试组织并遵循许多教程中显示的正确 Flask 文件夹结构和模块/导入。
我现在真的不知道为什么我在做某些事情,这从来都不是一件好事。
我的 Flask 应用布局如下:
/steam
run.py
/steamapp
__init__.py
config.py
tasks.py
views.py
/static
css.css
/templates
template.html
运行.py
from steamapp import app
app.run()
初始化.py
from celery import Celery
from config import secrets, constants
from flask.ext.openid import OpenID
from flask import Flask
import praw
def make_celery(app):
celery = Celery(app.import_name, backend='amqp', broker='amqp://guest@localhost//')
celery.conf.update(app.config)
TaskBase = celery.Task
class ContextTask(TaskBase):
abstract = True
def __call__(self, *args, **kwargs):
with app.app_context():
return TaskBase.__call__(self, *args, **kwargs)
celery.Task = ContextTask
return celery
app = Flask(__name__)
oid = OpenID(app)
app.debug = True
app.secret_key = secrets.APP_SECRET_KEY
celery = make_celery(app)
reddit = praw.Reddit(constants.USERAGENT)
reddit.login(constants.USERNAME, secrets.PASSWORD)
rs = praw.Reddit(constants.USERAGENT)
rs.set_oauth_app_info(secrets.CLIENT_ID, secrets.CLIENT_SECRET, constants.REDIRECT_URL)
from steamapp import views
from steamapp import tasks
View .py
from steamapp import app, oid, celery
from tasks import get_auth_url, check_reddit_oauth, request_steam_api
from flask import Flask, session, redirect, request, render_template, url_for
from config import secrets, constants
from flask.ext.openid import OpenID
import os
import praw
import time
import json
import string
import random
import requests
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def check_session_id(session):
if "id" in session:
return True
else:
return render_template("error.html", error=["?", "No session ID found."])
@app.route("/register")
def register():
if "id" not in session:
session["id"] = id_generator()
authorize_url = get_auth_url(session)
return redirect(authorize_url)
@app.route("/redirect/")
@oid.loginhandler
def redirect_to_steam_oauth():
...
...
...
etc
任务.py
from steamapp import celery, rs
from config import secrets, constants
import requests
@celery.task
def get_auth_url(session):
return rs.get_authorize_url(session["id"], scope="identity")
当我运行 run.py 时,我得到以下回溯:
Traceback (most recent call last):
File "/home/andy/Desktop/Python Projects/Finished/steam/run.py", line 1, in <module>
from steamapp import app
File "/home/andy/Desktop/Python Projects/Finished/steam/steamapp/__init__.py", line 25, in <module>
from steamapp import views
File "/home/andy/Desktop/Python Projects/Finished/steam/steamapp/views.py", line 20, in <module>
@app.route("/register")
NameError: name 'app' is not defined
我无法理解整体上发生的事情 - 我需要解释为什么我正在做我正在做的事情:
将
app.run()
分离到一个单独的 python 文件中的原因是什么,该文件从 steamapp 导入应用程序?为什么 app.run() 不在 views.py 中?init.py 的实际用途是什么?为什么要将
views.py
和tasks.py
导入其中?为什么在从
__init__.py
导入时给出“app”未定义的回溯?
感谢任何可以提供一些说明的人,因为我已经失去了对正在发生的事情的感觉。
编辑:
在阅读@dreamriver 的回复后,我已经用我所做的更改更新了 OP 中的代码。
我还是有点困惑——为什么我要在 views.py 中导入 flask,而它已经导入到 init.py 中, View 是从那里导入的,大概是从那里运行的?
此外,celery worker 如何与此相关联?将 tasks.py 设置为 Celery worker 会返回以下回溯:
celery -A tasks worker --loglevel=info
Traceback (most recent call last):
File "/usr/local/bin/celery", line 11, in <module>
sys.exit(main())
File "/usr/local/lib/python2.7/dist-packages/celery/__main__.py", line 30, in main
main()
File "/usr/local/lib/python2.7/dist-packages/celery/bin/celery.py", line 81, in main
cmd.execute_from_commandline(argv)
File "/usr/local/lib/python2.7/dist-packages/celery/bin/celery.py", line 769, in execute_from_commandline
super(CeleryCommand, self).execute_from_commandline(argv)))
File "/usr/local/lib/python2.7/dist-packages/celery/bin/base.py", line 305, in execute_from_commandline
argv = self.setup_app_from_commandline(argv)
File "/usr/local/lib/python2.7/dist-packages/celery/bin/base.py", line 465, in setup_app_from_commandline
self.app = self.find_app(app)
File "/usr/local/lib/python2.7/dist-packages/celery/bin/base.py", line 485, in find_app
return find_app(app, symbol_by_name=self.symbol_by_name)
File "/usr/local/lib/python2.7/dist-packages/celery/app/utils.py", line 229, in find_app
sym = symbol_by_name(app, imp=imp)
File "/usr/local/lib/python2.7/dist-packages/celery/bin/base.py", line 488, in symbol_by_name
return symbol_by_name(name, imp=imp)
File "/usr/local/lib/python2.7/dist-packages/kombu/utils/__init__.py", line 92, in symbol_by_name
module = imp(module_name, package=package, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/celery/utils/imports.py", line 101, in import_from_cwd
return imp(module, package=package)
File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
__import__(name)
File "/home/andy/Desktop/Python Projects/Finished/steam/steamapp/tasks.py", line 1, in <module>
from steamapp import celery, rs
ImportError: No module named steamapp
最佳答案
您必须明确地将应用程序导入到您的 View 文件中。错误说 app 没有在 views.py 中定义,那是因为你需要做:
from steamapp import app
在您的 View 文件的顶部。
__init__.py
将您的目录变成一个 python 包。在解释器启动时,所有在 $PYTHONPATH 上带有 __init__.py
的目录都被添加到 sys.path
中,这使得它们可以导入。 __init__.py
在导入它定义的模块时也会执行。这使得它非常有用,例如导出代码的主要 api。如果您查看 flask 的源代码,您会发现您所做的所有代码
from flask import Flask, request etc
实际上是在单独的文件中以较小的功能 block 定义的,然后在 __init__.py
中公开有趣的部分。
如前所述here Python 不希望包中的模块成为启动文件。 Python 打包有点乱。 This stackoverflow 的回答帮助我理解了其中的一些问题,即相对导入完全中断,因为它们是根据 __name__
计算的,当您直接执行文件时,它被设置为 '__main__'
但通过导入使用时是文件名本身。
除了像 __name__
和 __package__
这样的一些模块级全局变量之外,没有任何东西被显式地导入到顶级命名空间中。这就是为什么 app
在您的 views.py 文件中隐式地对您不可用。
这是否回答了您的问题?
编辑
您需要将 views.py 导入到 __init__.py
中,否则您的 views.py 文件将不会被执行,并且您的路由等都不会被定义。您需要将 app 导入 views.py,因为 app 不在您的 views.py 文件能够访问的命名空间中。这种两个文件相互导入的模式称为循环导入,可能很棘手,但在这里没问题。您应该知道,模块加载后会被缓存,因此在再次导入时不会重新执行。
你的 celery 问题在我看来是当 celery 启动时 python 在 sys.path
上看不到你的应用程序。此时显示 sys.path
的输出会很有帮助。我的猜测是,如果您将工作目录添加到 $PYTHONPATH,问题就会得到解决。当您使用 pip 等安装东西时,这些包将被添加到 python 默认情况下知道如何找到它们的地方。
关于python - 关于 Flask 和导入模块的困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26205514/