geekdoc-python-zh/docs/overiq/212.md

11 KiB
Raw Permalink Blame History

使用 Flask 脚本扩展 Flask

原文:https://overiq.com/flask-101/extending-flask-with-flask-script/

最后更新于 2020 年 7 月 27 日


Flask 加长件

Flask Extensions 指的是您可以安装来扩展 Flask 的包。Flask 扩展背后的想法是提供一种一致且可预测的方式来将包与 Flask 集成。要查看所有可用的分机,请访问http://flask.pocoo.org/extensions/。该页面包含从发送邮件到构建完整的管理界面的包。请记住,扩展 Flask 并不局限于 Flask Extensions事实上您可以使用 Python 标准库或 PyPI 中的任何包。本课的其余部分讨论如何安装和集成一个名为 Flask-Script 的有用的 Flask 扩展。

Flask-脚本扩展

Flask-Script 是一个不错的小扩展,它允许我们创建命令行界面、运行服务器、在应用上下文中启动 Python shell、使某些变量在 shell 中自动可用等等。

回想一下,在第课【Flask 基础知识】中,我们讨论过,为了在特定的主机和端口上运行开发服务器,我们需要将它们作为关键字参数传递给run()方法,如下所示:

if __name__ == "__main__":
    app.run(debug=True, host="127.0.0.10", port=9000)

问题是这种方法不是很灵活更好的方法是在启动服务器时将主机和端口作为命令行选项传递。Flask-Script 扩展允许我们这样做。不用多说,让我们通过输入以下命令来安装 Flask-Script:

(env) overiq@vm:~/flask_app$ pip install flask-script

要使用 Flask-Script首先从flask_script包导入Manager类,并通过向其传递应用实例来实例化Manager对象。这就是集成 Flask Extensions 的方法,从扩展包中导入必要的类,并通过将应用实例传递给它来实例化它。打开main2.py,修改文件如下:

Flask _app/main2.py

from flask import Flask, render_template
from flask_script import Manager

app = Flask(__name__)
manager = Manager(app)

...

我们刚刚创建的Manager对象也提供了run()方法,但是除了启动开发服务器之外,它还可以解析命令行参数。将线路app.run(debug=True)更换为manager.run()。此时main2.py应该是这样的样子:

Flask _app/main2.py

from flask import Flask, render_template
from flask_script import Manager

app = Flask(__name__)
manager = Manager(app)

@app.route('/')
def index():
    return render_template('index.html', name='Jerry')

@app.route('/user/<int:user_id>/')
def user_profile(user_id):
    return "Profile page of user #{}".format(user_id)

@app.route('/books/<genre>/')
def books(genre):
    return "All Books in {} category".format(genre)

if __name__ == "__main__":    
    manager.run()

我们的应用现在可以访问一些基本命令。要查看可用的命令,运行main2.py如下:

(env) overiq@vm:~/flask_app$ python main2.py
usage: main2.py [-?] {shell,runserver} ...

positional arguments:
  {shell,runserver}
    shell            Runs a Python shell inside Flask application context.
    runserver        Runs the Flask development server i.e. app.run()

optional arguments:
  -?, --help         show this help message and exit

如输出所示,目前我们有两个命令:shellrunserver。让我们从runserver命令开始。

runserver命令启动网络服务器。默认情况下,它在端口 5000 上的 127.0.0.1 启动开发服务器。查看任何命令的可用选项。键入--help,后跟命令名称。例如:

(env) overiq@vm:~/flask_app$ python main2.py runserver --help
usage: main2.py runserver [-?] [-h HOST] [-p PORT] [--threaded]
                          [--processes PROCESSES] [--passthrough-errors] [-d]
                          [-D] [-r] [-R] [--ssl-crt SSL_CRT]
                          [--ssl-key SSL_KEY]

Runs the Flask development server i.e. app.run()

optional arguments:
  -?, --help            show this help message and exit
  -h HOST, --host HOST
  -p PORT, --port PORT
  --threaded
  --processes PROCESSES
  --passthrough-errors
  -d, --debug           enable the Werkzeug debugger (DO NOT use in production
                        code)
  -D, --no-debug        disable the Werkzeug debugger
  -r, --reload          monitor Python files for changes (not 100% safe for
                        production use)
  -R, --no-reload       do not monitor Python files for changes
  --ssl-crt SSL_CRT     Path to ssl certificate
  --ssl-key SSL_KEY     Path to ssl key

runserver命令最常用的选项是--host--post,可以让我们在特定的接口和端口启动开发服务器。例如:

(env) overiq@vm:~/flask_app$ python main2.py runserver --host=127.0.0.2 --port 8000
 * Running on http://127.0.0.2:8000/ (Press CTRL+C to quit)

默认情况下,runserver命令在没有调试器和重新加载器的情况下启动服务器。我们可以手动打开调试器和重新加载器,如下所示:

(env) overiq@vm:~/flask_app$ python main2.py runserver -d -r
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 250-045-653
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

启动调试器和重新加载器的一个更简单的方法是将应用实例(app)的debug属性设置为True。打开main2.py,修改文件如下:

Flask _app/main2.py

#...
app = Flask(__name__)
app.debug = True
manager = Manager(app)
#...

现在我们来探索shell命令。

shell命令启动 Flask 应用上下文中的 Python Shell。这仅仅意味着应用和请求上下文提供的所有对象都可以在控制台中使用而无需创建应用或请求上下文。要启动 shell请输入以下命令。

>>>
(env) overiq@vm:~/flask_app$ python main2.py shell
>>>

现在让我们尝试访问一些对象。

>>>
>>> from flask import current_app, url_for, request
>>>
>>> current_app.name
'main2'
>>>
>>>
>>> url_for("user_profile", user_id=10)
'/user/10/'
>>>
>>> request.path
'/'
>>>

正如预期的那样,我们可以在不创建应用或请求上下文的情况下访问所需的对象。

创建命令

一旦创建了Manager实例,我们就可以创建自己的命令了。有两种方法可以创建命令:

  1. 使用Command类。
  2. 使用@command装饰器。

使用Command类创建命令

打开main2.py并添加Faker类,如下所示:

Flask _app/main2.py

#...
from flask_script import Manager, Command
#...

manager = Manager(app)

class Faker(Command):
    'A command to add fake data to the tables'
    def run(self):
        # add logic here
        print("Fake data entered")

@app.route('/')
#...

这里我们通过继承Command类创建了一个命令Faker。执行命令时会调用run()方法。现在,要从命令行运行该命令,请使用add_command()方法将其添加到Manager实例,如下所示:

Flask _app/main2.py

#...
class Faker(Command):
    'A command to add fake data to the tables'
    def run(self):
        # add logic here
        print("Fake data entered")

manager.add_command("faker", Faker())
#...

现在返回终端,再次运行main2.py:

(env) overiq@vm:~/flask_app$ python main2.py
usage: main2.py [-?] {faker,shell,runserver} ...

positional arguments:
  {faker,shell,runserver}
    faker               A command to add fake data to the tables
    shell               Runs a Python shell inside Flask application context.
    runserver           Runs the Flask development server i.e. app.run()

optional arguments:
  -?, --help            show this help message and exit

注意,除了shellrunserver,我们现在还有一个faker命令的条目。faker 命令前面的描述来自Faker类中的 doc 字符串。要运行它,请输入以下命令:

(env) overiq@vm:~/flask_app$ python main2.py faker
Fake data entered

使用@command装饰器创建命令

使用Command类创建命令有点冗长。或者,我们可以使用Manager实例的@command装饰器。打开main2.py,修改文件如下:

Flask _app/main2.py

#...
manager.add_command("faker", Faker())

@manager.command
def foo():
    "Just a simple command"
    print("foo command executed")

@app.route('/')
#...

我们已经创建了一个简单的命令foo,当被调用时会打印foo command executed@command装饰器会自动将命令添加到现有的Manager实例中,因此我们不需要调用add_command()方法。再次返回终端,运行main2.py文件查看命令使用情况。

(env) overiq@vm:~/flask_app$ python main2.py 
usage: main2.py [-?] {faker,foo,shell,runserver} ...

positional arguments:
  {faker,foo,shell,runserver}
    faker               A command to add fake data to the tables
    foo                 Just a simple command
    shell               Runs a Python shell inside Flask application context.
    runserver           Runs the Flask development server i.e. app.run()

optional arguments:
  -?, --help            show this help message and exit

如您所见,我们的foo命令现在可用,我们可以通过输入以下命令来执行它。

(env) overiq@vm:~/flask_app$ python main2.py foo
foo command executed

自动导入对象

在一个 shell 中导入大量对象可能会很乏味。使用 Flask-Script我们可以在不显式导入对象的情况下使对象在 Shell 内可用。

Shell命令启动一个 Shell。Shell构造函数接受一个名为make_context的关键字参数。传递给make_context的参数必须是返回字典的可调用参数。默认情况下,可调用返回一个只包含应用实例的字典,即app。这意味着,默认情况下,在 shell 中,您只能访问应用实例(app),而不能显式导入它。要覆盖这个缺省值,给make_context分配一个新的可调用函数,它会返回一个你想在 shell 中访问的对象的字典。

打开main2.py,在foo()功能后添加如下代码。

Flask _app/main2.py

#...
from flask_script import Manager, Command, Shell

#...
def shell_context():
    import os, sys
    return dict(app=app, os=os, sys=sys)

manager.add_command("shell", Shell(make_context=shell_context))
#...

这里我们给make_context关键字参数分配一个名为shell_context的可调用函数。shell_context()函数返回包含三个对象的字典:appossys。因此,在 shell 中,我们可以访问这些对象,而无需显式导入它们。

(env) overiq@vm:~/flask_app$ python main2.py shell
>>>
>>> app
<Flask 'main2'>
>>>
>>> os.name
'posix'
>>>
>>> sys.platform
'linux'
>>>
>>>