Flask框架学习笔记

本文档介绍了Flask的基本用法,包括创建简单应用、启动Web服务、配置、URL路由、HTTP方法、静态文件、模板渲染、请求数据处理、文件上传、Cookie、重定向、错误处理、API设计、Session管理以及Message Flashing。还涉及了logging日志和一些高级功能如API与JSON、会话和数据验证。
摘要由CSDN通过智能技术生成

Flask框架学习笔记

1. 最简单的flask例子

# 文件名不可取为flask.py,以免发生冲突,本实例以hello.py为代表
from flask import Flask #对象的实例是 WSGI 
app = Flask(__name__) # 如果使用单一模块,使用__name__;取决于是作为应用程序的起始还是作为引入的模块,

@app.route('/') # route()是告诉flask哪个url要被触发
def hello_world():
    return 'Hello, World!'

2. 如何用命令启动web

# 应该在项目的路径上执行以下方法,而不是在包的路径下
# 方法1:用flask命令启动
$ export FLASK_APP=hello.py
$ flask run
 * Running on http://127.0.0.1:5000/
# 方法2:用python -m代替flask命令
$ export FLASK_APP=hello.py
$ python -m flask run
 * Running on http://127.0.0.1:5000/
# 若上述方法无效,可能有以下原因:
1. flask版本太旧(<0.11)——升级版本或查看旧版本的启动方式
2. 引入了不合法的名称
# 在window中,set代替export

3. 常用配置

# 在命令行添加以下代码,可使服务公开,可使程序监听所有ip
$ flask run --host=0.0.0.0
# 当代码发生改变时,代码会重新加载启动,且若出现问题将提供一个调试器(注:在window下要用set代替export)
$ export FLASK_ENV=development
$ flask run
# 上述代码可做一下事情:
# 1、触发debugger 2、自动重加载 3、在flask应用上debug

# 使debug与flask环境分离
exporting FLASK_DEBUG=1.

注意:不能在生产环境中使用,有安全风险

4. URL

# 可以在url中增加 <variable_name>变量名,该变量将作为一个关键字参数被方法接收。还可以使用一个转换器来指定参数的类型,如<converter:variable_name>

from markupsafe import escape

@app.route('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    return 'User %s' % escape(username)

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id

@app.route('/path/<path:subpath>')
def show_subpath(subpath):
    # show the subpath after /path/
    return 'Subpath %s' % escape(subpath)

  # converter类型:string、int、float、path、uuid
# 唯一的url/重定向行为
# 在下述的两个方法中
# 第一个projects结尾处有斜杠,类似于文件夹。若访问时没有带/,则Flask将重定向到结尾带/的url
# 第二个abiut结尾处没有斜杠,类似于文件。若使用末尾斜杠访问URL会产生404 " Not Found "错误
# 以上有助于保持这些资源的url的唯一性,这有助于搜索引擎避免索引相同的页面两次。
@app.route('/projects/')
def projects():
    return 'The project page'

@app.route('/about')
def about():
    return 'The about page'
# 构建url
# 使用url_for()方法。它接受函数名作为第一个参数和任意数量的关键字参数,每个参数对应于URL规则的一个变量部分。未知的变量部分作为查询参数附加到URL中,返回对应的url
# 为什么不使用硬编码的方式构建url?
# 原因1、更具有描述性 2、可以一次性改变url,而不是手动改变硬编码 3、更好地处理特殊字符和Unicode数据的转义 4、生成绝对路径,避免相对路径在浏览器中发生意外的行为 5、可以正确处理在根目录之外的应用程序位置

from flask import Flask, url_for
from markupsafe import escape

app = Flask(__name__)

@app.route('/')
def index():
    return 'index'

@app.route('/login')
def login():
    return 'login'

@app.route('/user/<username>')
def profile(username):
    return '{}\'s profile'.format(escape(username))

with app.test_request_context():
    print(url_for('index'))
    print(url_for('login'))
    print(url_for('login', next='/'))
    print(url_for('profile', username='John Doe'))

输出:
/
/login
/login?next=/
/user/John%20Doe

5. HTTP方法

# HTTP方法
# 默认是Get方法,可在route中添加HTTP方法
# 方法对应的Header、Option等会自动添加
from flask import request

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        return do_the_login()
    else:
        return show_the_login_form()

6. 静态文件

# 静态文件放置js和css文件
# 使用下列代码,将加载static/style.css文件
url_for('static', filename='style.css')

7. 渲染模板

# 在Python中生成HTML必须自己进行HTML转义,不方便且不安全。Flask配置Jinja2模板引擎。要渲染一个模板,可以使用render_template()方法。只需要提供模板的名称和要作为关键字参数传递给模板引擎的变量。
from flask import render_template

@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
    return render_template('hello.html', name=name)
# Flask将从templates文件夹查找模板。若原程序是一个module,则templates文件夹位于程序的旁边文件夹;若原程序是一个package,则templates文件夹在package里面。可使用Jinja2模板引擎的全部功能,以下为一个例子:
<!doctype html>
<title>Hello from Flask</title>
{% if name %}
  <h1>Hello {{ name }}!</h1>
{% else %}
  <h1>Hello, World!</h1>
{% endif %}
# 模板可继承,用于页面内固定元素
# 自动转义是启用的,所以如果name包含HTML,它将自动转义。如果信任一个变量,并且知道它是安全的HTML(例如,因为它来自一个将wiki标记转换为HTML的模块),可通过使用markup类或模板中的|safe过滤器将它标记为安全的。
>>> from markupsafe import Markup
>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
Markup(u'<strong>Hello &lt;blink&gt;hacker&lt;/blink&gt;!</strong>')
>>> Markup.escape('<blink>hacker</blink>')
Markup(u'&lt;blink&gt;hacker&lt;/blink&gt;')
>>> Markup('<em>Marked up</em> &raquo; HTML').striptags()
u'Marked up \xbb HTML'

8. 访问请求数据

Flask中提供全局的request对象

# Flask中的全局变量不是常用类型,这些对象实际上是特定上下文本地对象的代理。
# 假设上下文是处理线程。请求传入后,web服务器决定生成一个新线程(或其他东西,底层对象能够处理线程以外的并发系统)。当Flask开始其内部请求处理时,它会发现当前线程是活动的context,并将当前应用程序和WSGI环境绑定到该context(线程)。它以一种智能的方式做到这一点,以便一个应用程序可以调用另一个应用程序而不会中断。因此,可以忽略,除非你在做一些类似单元测试的事情。您将注意到依赖于请求对象的代码将突然中断,因为没有请求对象。解决方案是自己创建一个请求对象并将其绑定到上下文。单元测试最简单的解决方案是使用test_request_context()上下文管理器。与with语句结合使用,它将绑定一个测试请求,以便与之交互。下面是一个例子:
from flask import request

with app.test_request_context('/hello', method='POST'):
    # now you can do something with the request until the
    # end of the with block, such as basic assertions:
    assert request.path == '/hello'
    assert request.method == 'POST'

# 另一种方式是将整个WSGI环境传递给request_context()方法
from flask import request

with app.request_context(environ):
    assert request.method == 'POST'

9. Request对象

# 访问表单数据(在POST或PUT请求中传输的数据),可以使用form属性。
from flask import request
@app.route('/login', methods=['POST', 'GET'])
def login():
    error = None
    if request.method == 'POST':
        if valid_login(request.form['username'],
                       request.form['password']):
            return log_the_user_in(request.form['username'])
        else:
            error = 'Invalid username/password'
    # the code below is executed if the request method
    # was GET or the credentials were invalid
    return render_template('login.html', error=error)
# 获取URL的参数
searchword = request.args.get('key', '')

当key不存在时,会抛出KeyError错误,应该不主动捕捉错误,否则会有400页面。

10. 文件上传

要确保HTML的form中有enctype="multipart/form-data"属性。

from flask import request

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['the_file']
        f.save('/var/www/uploads/uploaded_file.txt')
    ...
from flask import request
from werkzeug.utils import secure_filename

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['the_file']
        f.save('/var/www/uploads/' + secure_filename(f.filename)) # 查看文件在客户端的文件名,但该名字不能被信任,可先通过secure_filename()方法再传递
    ...

11. Cookie

# 可以通过cookies属性来访问cookies
# 读取cookies
from flask import request

@app.route('/')
def index():
    username = request.cookies.get('username')
    # use cookies.get(key) instead of cookies[key] to not get a
    # KeyError if the cookie is missing.
# 存储cookies
from flask import make_response

@app.route('/')
def index():
    resp = make_response(render_template(...))
    resp.set_cookie('username', 'the username')
    return resp

12. 重定向和错误

from flask import abort, redirect, url_for

@app.route('/')
def index():
    return redirect(url_for('login')) # 重定向

@app.route('/login')
def login():
    abort(401) # 以错误代码终止请求
    this_is_never_executed()
    
# 默认情况下,每个错误代码都会显示一个黑白错误页面。如果你想自定义错误页面,你可以使用errorhandler()装饰器
from flask import render_template

@app.errorhandler(404)
def page_not_found(error):
    return render_template('page_not_found.html'), 404

13. Response

返回值会自动转换成一个response对象。

  1. 如果返回了正确类型的响应对象,它将直接从视图返回

  2. 如果是字符串,则创建一个带有该数据和默认参数的响应对象

  3. 如果是一个dict,则使用jsonify创建一个响应对象

  4. 如果一个元组被返回,元组中的项可以提供额外的信息。这样的元组必须以(response, status)(response, headers)或者 (response, status, headers)的形式存在。状态值将覆盖状态代码,并且头可以是附加头值的列表或字典。

  5. 如果这些都不起作用,Flask将假定返回值是一个有效的WSGI应用程序,并将其转换为一个响应对象。

# 如果想在视图中获取得到的响应对象,可以使用make_response()函数。
def not_found(error):
    resp = make_response(render_template('error.html'), 404)
    resp.headers['X-Something'] = 'A value'
    return resp

14. APIs with JSON

# 返回dict,将转换为json
@app.route("/me")
def me_api():
    user = get_current_user()
    return {
        "username": user.username,
        "theme": user.theme,
        "image": url_for("user_image", filename=user.image),
    }
# 为dict以外的类型创建JSON响应可使用jsonify()函数,它将序列化任何支持的JSON数据类型
@app.route("/users")
def users_api():
    users = get_all_users()
    return jsonify([user.to_json() for user in users])

15. Session

# sessions在cookies上实现
from flask import Flask, session, redirect, url_for, request
from markupsafe import escape

app = Flask(__name__)

# Set the secret key to some random bytes. Keep this really secret!
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/' # 为了使用session,必须有secret_key

@app.route('/')
def index():
    if 'username' in session:
        return 'Logged in as %s' % escape(session['username'])
    return 'You are not logged in'

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect(url_for('index'))
    return '''
        <form method="post">
            <p><input type=text name=username>
            <p><input type=submit value=Login>
        </form>
    '''

@app.route('/logout')
def logout():
    # remove the username from the session if it's there
    session.pop('username', None)
    return redirect(url_for('index'))
  
# 关于基于cookie的会话的注意事项:Flask将获取您放入会话对象中的值,并将它们序列化到一个cookie中。如果您发现一些值在请求之间不持久,那么确实启用了cookie,并且没有得到明确的错误消息,请检查页面响应中的cookie大小,并与web浏览器支持的大小进行比较。

16. 消息闪烁Message Flashing

用这个闪烁系统向用户提供反馈。闪烁系统基本上可以在请求结束时记录一条消息,并在下一个(仅下一个)请求中访问该消息。这通常与布局模板结合使用来公开消息。使用flash()方法来获取消息,你可以使用get_flashhed_messages(),它也可以在模板中找到。

17. Logging日志

app.logger.debug('A value for debugging')
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('An error occurred')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值