具体实现方法如下:
在 Flask 项目的入口文件中,导入 werkzeug.serving 模块中的 run_simple 函数
Werkzeug 是一个 Python 的 WSGI 工具库,它可以用来构建 Web 应用程序。
from werkzeug.serving import run_simple
使用 run_simple 函数启动 Flask 服务器,并设置 use_reloader=True 表示启用自动重载:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
if __name__ == '__main__':
app.run(debug=True, use_reloader=True)
from werkzeug.wrappers import Request, Response
@Request.application
def application(request):
return Response('Hello world')
if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost', 5000, application)
使用 @Request.application 装饰器将 application 函数转换为一个 WSGI 应用程序。然后使用
run_simple 函数在本地的 5000 端口运行应用程序。
def run_simple(hostname, port, application, use_reloader=False,
use_debugger=False, use_evalex=True,
extra_files=None, reloader_interval=1, threaded=False,
processes=1, request_handler=None, static_files=None,
passthrough_errors=False, ssl_context=None):
# 这方法还是比较短的,但是注释写得很详细,由于篇幅问题,就把源码中的注释省略了
if use_debugger:
from werkzeug.debug import DebuggedApplication
application = DebuggedApplication(application, use_evalex)
if static_files:
from werkzeug.wsgi import SharedDataMiddleware
application = SharedDataMiddleware(application, static_files)
def inner():
make_server(hostname, port, application, threaded,
processes, request_handler,
passthrough_errors, ssl_context).serve_forever()
if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
display_hostname = hostname != '*' and hostname or 'localhost'
if ':' in display_hostname:
display_hostname = '[%s]' % display_hostname
_log('info', ' * Running on %s://%s:%d/', ssl_context is None
and 'http' or 'https', display_hostname, port)
if use_reloader:
# Create and destroy a socket so that any exceptions are raised before
# we spawn a separate Python interpreter and lose this ability.
test_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
test_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
test_socket.bind((hostname, port))
test_socket.close()
run_with_reloader(inner, extra_files, reloader_interval)
else:
inner()
虽然 jinja2 是一个单独的库,但是由于 flask 依赖了jinja2,所以不必单独安装。
from flask import render_template
使用
@app.route('/template')
def template(): # put application's code here
// 渲染
return render_template('demo.html')
动态渲染
还是使用 jinja2 的 render_template
通过blog_id 与 HTML中 {{ blog_id }} 关联
@app.route('/template/blog/' )
def template(blog_id): # put application's code here
return render_template('demo.html', blog_id=blog_id)
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Titletitle>
head>
<body>
<a href="www.baidu.com">百度a>
<div class="header">这里是博客{{ blog_id }}div>
body>
html>
@app.route('/template/blog/' )
def template(blog_id): # put application's code here
uesr = User('lijiajun', '[email protected]')
person = {
'username': 'zhangsan',
'email': 'zhangsan的email'
}
return render_template('demo.html', blog_id=blog_id, user=uesr, person=person)
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Titletitle>
head>
<body>
<a href="www.baidu.com">百度a>
<div class="header">这里是博客{{ blog_id }}div>
<div>{{ user }}div>
<div>{{ user.username }}div>
<div>{{ user.email }}div>
<div>{{ person.username }}div>
<div>{{ user.email }}div>
body>
html>
使用过滤器
使用管道符号 | 即可。
def filter(value):
return value.upper()
# 增加过滤器
app.add_template_filter(filter, 'filter')
<div>{{ user.email | filter }}</div>
jinja2的语句
<div>
{% if age > 18 %}可以进入 {% endif %} {% if age < 18 %} 禁止进入{% endif %}
div>
<div>
{% for foo in age %}
{% endfor %}
div>
组件传参
demo.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>testtitle>
head>
<body>
<div>
{% extends 'component.html' %} {% block content %} 我是传过来的内容 {%
endblock %} {% block title %} 我是传过来的标题 {% endblock %}
div>
body>
html>
component.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>这是一个组件title>
head>
<body>
这是一个组件 {% block title %}{% endblock %} {% block content %}{% endblock
%}
body>
html>
加载图片
<body>
<div>
<img src='{{ url_for("static",filename="image.png") }}' alt="" />
div>
body>
加载Css文件
<head>
<meta charset="UTF-8" />
<title>testtitle>
<link rel="stylesheet" href='{{ url_for("static",filename="demo.css") }}' />
head>
加载Js文件
<script src='{{ url_for("static",filename="demo.js")}}'>script>
pip install pymysql
我们不会直接使用这个包去操作数据库,因为需要写原生的SQL语句,我们最好使用 orm。
所以我们还需要下一个:
pip install flask-sqlalchemy
sqlalchemy 给我们提供了 orm 的技术,可以让我们像操作普通对象一样去操作数据库。
这个需要额外安装,因为 flask 没有这个依赖。
from flask_sqlalchemy import SQLAlchemy
创建SQLAlchemy实例对象,命名为db,将flask的实例对象app作为参数传给SQLAlchemy,将db和app联系起来,可以调用其相关功能
db = SQLAlchemy(app)
gunicorn app:app -c gunicorn.conf.py > gun.log 2>&1 &
一 Gunicorn是基于unix系统,被广泛应用的高性能的Python WSGI HTTP Server。用来解析HTTP请求的网关服务。
它通常是在进行反向代理(如nginx),或者进行负载均衡(如 AWS ELB)和一个web 应用(比如 Django 或者 Flask)之间。
它的运行模型基于pre-fork worker 模型,即就是支持eventlet,也支持greenlet。
二、gunicorn特点
其特点:1、能和大多数的Python Web框架兼容;
2、简单易上手;
3、轻量级的资源消耗;
4、目前,gunicorn只能运行在Linux环境中,不支持windows平台
gunicorn -w 5 -b 0.0.0.0:6000 main:app
解释下参数含义:
-w :表示工作进程数
-b :访问地址和端口
main :flask启动python文件名
app :脚本中创建的Flask对象名
from flask import Flask
app = Flask(__name__)
@app.route('/',methods=['GET'])
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=6000)
也可以根据文件启动
gunicorn -c config.py main:app
cat config.py
# 是否开启debug模式
debug = True
# 访问地址
bind = "0.0.0.0:6000"
# 工作进程数
workers = 2
# 工作线程数
threads = 2
# 超时时间
timeout = 600
# 输出日志级别
loglevel = 'debug'
# 存放日志路径
pidfile = "log/gunicorn.pid"
# 存放日志路径
accesslog = "log/access.log"
# 存放日志路径
errorlog = "log/debug.log"
# gunicorn + apscheduler场景下,解决多worker运行定时任务重复执行的问题
preload_app = True
-c CONFIG : CONFIG,配置文件的路径,通过配置文件启动;生产环境使用;
-b ADDRESS : ADDRESS,ip加端口,绑定运行的主机;
-w INT, --workers INT:用于处理工作进程的数量,为正整数,默认为1;
-k STRTING, --worker-class STRTING:要使用的工作模式,默认为sync异步,可以下载eventlet和gevent并指定
--threads INT:处理请求的工作线程数,使用指定数量的线程运行每个worker。为正整数,默认为1。
--worker-connections INT:最大客户端并发数量,默认情况下这个值为1000。
--backlog int:未决连接的最大数量,即等待服务的客户的数量。默认2048个,一般不修改;
-p FILE, --pid FILE:设置pid文件的文件名,如果不设置将不会创建pid文件
--access-logfile FILE : 要写入的访问日志目录
--access-logformat STRING:要写入的访问日志格式
--error-logfile FILE, --log-file FILE : 要写入错误日志的文件目录。
--log-level LEVEL : 错误日志输出等级。
--limit-request-line INT : HTTP请求头的行数的最大大小,此参数用于限制HTTP请求行的允许大小,默认情况下,这个值为4094。值是0~8190的数字。
--limit-request-fields INT : 限制HTTP请求中请求头字段的数量。此字段用于限制请求头字段的数量以防止DDOS攻击,默认情况下,这个值为100,这个值不能超过32768
--limit-request-field-size INT : 限制HTTP请求中请求头的大小,默认情况下这个值为8190字节。值是一个整数或者0,当该值为0时,表示将对请求头大小不做限制
-t INT, --timeout INT:超过这么多秒后工作将被杀掉,并重新启动。一般设定为30秒;
--daemon: 是否以守护进程启动,默认false;
--chdir: 在加载应用程序之前切换目录;
--graceful-timeout INT:默认情况下,这个值为30,在超时(从接收到重启信号开始)之后仍然活着的工作将被强行杀死;一般使用默认;
--keep-alive INT:在keep-alive连接上等待请求的秒数,默认情况下值为2。一般设定在1~5秒之间。
--reload:默认为False。此设置用于开发,每当应用程序发生更改时,都会导致工作重新启动。
--spew:打印服务器执行过的每一条语句,默认False。此选择为原子性的,即要么全部打印,要么全部不打印;
--check-config :显示现在的配置,默认值为False,即显示。
-e ENV, --env ENV: 设置环境变量;