1+1=10

扬长避短 vs 取长补短

Python flask入门笔记(四)

前面在了解Sessions时接触到SECRET_KEY这一个配置项目,继续看看其他相关配置项

Config

一个Flask的应用程序需要这样那样的配置。这个配置通过Flask对象的config属性来实现。

比如,要启用debug选项

from flask import Flask

app = Flask(__name__)
app.config['DEBUG'] = True

部分内置的配置变量:

  • DEBUG:在开发server中启动调试
  • TESTING
  • SECRET_KEY:session机制需要这个。可使用secrets生成,import secrets; print(secrets.token_hex())
  • SESSION_COOKIE_DOMAIN
  • SERVER_NAME:subdmain机制需要这个东西。设置后url_for可以依据app上下文生成外部url,而不需要request上下文。
  • APPLICATION_ROOT:默认/
  • PREFERRED_URL_SCHEME:默认 http
  • ...

除了通过Flask对象的config属性设置。还可以直接通过Flask对象直接配置,比如

app = Flask(__name__)
app.debug = True

或者通过环境变量设置

  • powershell:
$env:FLASK_DEBUG = "true"
flask run
  • bash:
export FLASK_DEBUG=true

对于DEBUG,一般命令行也可以配置:

$ flask run --debug

注意,注意:这个例子使用DEBUG举例,有一定的问题。DEBUG和其他变量相比,比较特殊。一般都需要在命令行或启动时指定,不然debuger可能不生效(尽管在config中进行了配置后,你再读取它,返回的也是设置值)。

成员函数

flask的Config还有其他成员:

  • from_pyfile:加载配置文件
  • from_object
  • from_envvar:环境变量指定一配置文件路径(内部使用from_pyfile逻辑)
  • from_file:加载其他格式,比如json、toml等。而后用from_mapping?
  • from_mapping
  • from_prefixed_env:加载FLASK_开头的环境变量,并去除前缀。

我们有一个配置文件config.py(注意,大写的变量。其他变量不会导出):

# config.py for demo
SECRET_KEY = '1/234131/341b3209dda'

而后可以

app = Flask(__name__)
app.config.from_object('config')

app = Flask(__name__)
app.config.from_pyfile('config.py')

开发、生产

多数程序都有不止一个配置文件。至少需要为开发和生成使用不同的配置

  • 可通过环境变量指向配置文件
MYAPPLICATION=/path/to/config.py
  • 可通过环境变量定义模式production、development,代码中针对不同模式加载不同配置

Flask建议操作:

  1. 在源码管控中保留一份默认配置
  2. 使用环境变量来切换配置
  3. 将代码和配置 分别推送到生产服务器

实例文件夹(Instance folder)

Flask 0.8引入了实例文件夹。实例文件夹和发布相关,不应该再源码管控内(将其加入到.gitignore中)。

在创建 Flask 应用时可以显式地提供实例文件夹的路径,定义使用 instance_path 参数:

app = Flask(__name__, instance_path='/path/to/instance/folder')

也可以让 Flask 自动探测实例文件夹(和模板文件夹类似),它位于:

/myapp.py
/instance

在创建 Flask 应用时可以配置instance_relative_config=True

app = Flask(__name__, instance_relative_config=True)
app.config.from_object('config1')
app.config.from_pyfile('config2.py')

这将会从instance目录下加载config2.py文件。

注意:上面的代码中config1.py继续从非实例文件夹中加载,通过from_object,与from_pyfile行为不同:

/myapp.py
/config1.py
/instance/config2.py

SERVER_NAME

回归本文初衷,Flask配置中有一项,SERVER_NAME,关注它是由于它和routing中的subdomain直接相关。

Subdomain

作为本地测试,先修改hosts文件:

  • /etc/hosts
  • C:\Windows\System32\Drivers\etc\hosts
127.0.0.1 mypc.local
127.0.0.1 d.mypc.local
127.0.0.1 e.mypc.local
127.0.0.1 b.mypc.local
127.0.0.1 a.mypc.local
127.0.0.1 o.mypc.local

写一个flask程序:

from flask import Flask, request, redirect, url_for

app = Flask(__name__)
app.config['SERVER_NAME'] = 'mypc.local:8000'

@app.route('/')
def index():
    return "Hello World!"

@app.route('/', subdomain='<subdomain>')
def home(subdomain):
    return f"Hello {subdomain}!"

if __name__ == '__main__':
    app.run(port=8000, debug=True)

这样,通过浏览器访问

  • mypc.local:8000 ,看到"Hello World!"
  • d.mypc.local:8000,看到"Hello d!"
  • e.mypc.local:8000,看到”Hello e!"
  • ...

subdomain 是相对于SERVER_NAME来说的。注意,它包括端口号。

注意,一旦设置了SERVER_NAME,Flask不响应其他的地址,比如:

from flask import Flask, request, redirect, url_for

app = Flask(__name__)
app.config['SERVER_NAME'] = 'mypc.local:8000'


@app.route('/')
def index():
    return "Hello World!"

如果试图通过d.mypc.local:8000访问,会收到404错误页面。

注:除了subdomain匹配,Flask还有 host_matching的机制。

url_for

手册上提到,设置SERVER_NAME后,url_for生成外部路径时将不依赖于request上下文

from flask import Flask, request, redirect, url_for

app = Flask(__name__)
app.config['SERVER_NAME'] = 'mypc.local:8000'

@app.route('/')
def index():
    return "Hello World!"

with app.test_request_context():
    print(url_for('index', _external=True))

小结

到目前为止,只涉及...

/myapp.py
/templates/
/instance/config.py

这些路径在flask程序中都可以修改。

参考

  • https://github.com/pallets/flask
  • https://flask.palletsprojects.com
  • https://flask.palletsprojects.com/en/3.0.x/config/
  • https://uniwebsidad.com/libros/explore-flask/chapter-5/instance-folder

Comments