likes
comments
collection
share

python-Flask框架基础学习

作者站长头像
站长
· 阅读数 13

Flask简介

  Flask是一个基于Python开发而且依赖jinja2模板和Werkzeug WSGI服务的一个微型Web框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,而后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,若是要返回给用户复杂的内容时,须要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。

​ Flask被设计为易于使用,同时也提供了扩展性,用户可以自由地选择将其与哪些第三方库集成。Flask是"微"框架,这意味着其核心功能非常有限,但可以通过一系列的扩展来增强功能。

Flask基本使用

安装与使用示例

pip install flask

让我们来看一下如何创建一个简单的Flask应用。

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

if __name__ == '__main__':
    app.run()

在这段代码中,我们首先导入Flask模块,并创建一个Flask web服务器实例。然后,我们定义了一个路由(route),即/。这个路由映射到一个函数hello_world,当用户访问这个URL时,它会返回'Hello, World!'字符串。

Flask路由

Flask通过提供装饰器app.route,使得定义路由变得简单易行。但你知道我们也可以通过app.add_url_rule方法直接添加路由吗?这种方式提供了更多的灵活性,例如,可以为路由添加不同的HTTP方法。

from flask import Flask

app = Flask(__name__)


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

# view_func必填
app.add_url_rule('/index', view_func=index)

if __name__ == '__main__':
    app.run()

在上述代码中,app.add_url_rule的第一个参数是URL规则,第二个参数是函数的别名,第三个参数是要映射的函数。

  route参数

from flask import Flask

app = Flask(__name__)

"""
rule: 路由路径
methods: 请求方式
endpoint: 起别名, 用于反向解析. url_for('index')
strict_slashes: 设置路由是否为严格模式, True为严格模式, False为非严格模式, 默认为True
	如果关闭 /hello和/hi/都被视为有效的URL

"""
@app.route('/index', methods=["GET", "POST"], endpoint='index', strict_slashes=True)
def index():
    return "index"

# app.add_url_rule('/index', view_func=index)
"""
self.add_url_rule(rule, endpoint, f, **potion)参数以下

self: Flask类产生的对象(app)
rule: 路由
endpoint: 取别名, 若是为空, 用当前的函数名
methods: 请求方式
view_func: 取别名指向的函数(请求该路径, 要响应的函数)
"""

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


if __name__ == '__main__':
    app.run()

路由装饰器

 # 装饰器函数
 def route(self, rule, **options):

        def decorator(f):
            endpoint = options.pop("endpoint", None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f

        return decorator

# 被装饰函数
@app.route('/login',methods=['POST', "GET"], endpoint='index')
def login():
    return "hello world"

装饰器: 先执行装饰器, 运行里面的代码, 返回一个函数名
        而后加括号, 把装饰器装饰的函数当成参数传递给函数,
        返回一个被装饰器装饰的同名函数

   路由跳转

from flask import Flask, url_for, redirect

app = Flask(__name__)


@app.route('/home', endpoint='home')
def home():
    return 'Hello World!'


@app.route('/index')
def index():
    # url_for函数用于建立URL的反向解析,它可以根据视图函数的名称生成对应的URL。
    # 使用url_for可以有效地避免硬编码URL地址,提高代码的可维护性
    return redirect(url_for('home'))


if __name__ == '__main__':
    app.run()

  路由参数

from flask import Flask, jsonify

app = Flask(__name__)
app.debug = True

USERS = {
    1: {'name': '张三', 'age': 18, 'gender': '男', 'text': "道路千万条"},
    2: {'name': '李四', 'age': 28, 'gender': '男', 'text': "安全第一条"},
    3: {'name': '王五', 'age': 18, 'gender': '女', 'text': "行车不规范"},
}


@app.route('/detail/<int:nid>', methods=['GET'], endpoint='detail')
def detail(nid):
    print(nid, type(nid))
    return jsonify(USERS[nid])


if __name__ == '__main__':
    app.run()

Flask模板

Flask使用jinja2模板库。这个库非常强大,可以让你在HTML中嵌入Python代码。下面的例子展示了如何在Flask应用中使用模板:

# python
from flask import Flask
from flask import render_template

app = Flask(__name__)


@app.route('/hello')
def hello():
    name = '你好呀!'
    return render_template('hello.html', name=name)


if __name__ == '__main__':
    app.run()

render_template函数用于渲染一个模板。它接收模板的名称和一些模板变量作为参数,返回生成的HTML内容。在模板中,你可以使用{{ name }}来显示变量的值。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{{ name }}
</body>
</html>

  模板显示HTML

"""
一种: .py文件渲染标签, 导入Markup
二种: 前端页面{{ html|safe }}
"""
from flask import Flask, Markup, render_template

app = Flask(__name__)
app.debug = True

def func(st1, st2):
	#Markup类用于在模板中输出HTML代码 
    ''' flask 3的版本中不再提供 可以改成
    from jinja2.utils import markupsafe
    markupsafe.Markup(html)
    ''' # |safe 也可以讲字符串以html格式输出
    return Markup(f"<h1>{st1} {st2}!</h1>")

@app.route('/index')
def index():
    html = "<h1>you are beautiful!</h1>"
    return render_template('index.html', func=func, html=html)

if __name__ == '__main__':
    app.run()

  html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{{ func('hello', 'world') }}
{{ html|safe}}
{# safe过滤器用于告诉模板引擎将一个字符串作为原始的HTML代码进行渲染,而不是对其进行转义处理  #}
</body>
</html>

Flask 请求方式

from flask import request

@app.route('/', methods=['GET'])
def get_handler():
    # 处理GET请求逻辑
    return 'This is a GET request'
from flask import request

@app.route('/', methods=['POST'])
def post_handler():
    # 处理POST请求逻辑
    return 'This is a POST request'
from flask import request

@app.route('/', methods=['GET', 'POST'])
def handler():
    if request.method == 'GET':
        # 处理GET请求逻辑
        return 'This is a GET request'
    elif request.method == 'POST':
        # 处理POST请求逻辑
        return 'This is a POST request'

Flask请求与响应

from flask import Flask
from flask import request
from flask import make_response
from flask import render_template
from flask import redirect

   请求

request.args  # get请求提交的数据
# 用于获取GET请求中的查询参数。例如,对于URL example.com?name=John&age=25,可以使用request.args.get('name')来获取参数值 'John'。
    
request.form  # post请求提交的数据
# 用于获取POST请求中的表单数据。当客户端向服务器发送一个POST请求并提交表单数据时,可以使用request.form.get('key')来获取表单字段的值。
    
request.values  # post和get提交的数据都在
# 用于获取GET和POST请求中的所有参数值。既包括查询参数也包括表单数据。可以使用request.values.get('key')来获取参数值
    
request.cookies  # 客户端携带cookie
# 用于获取客户端请求中携带的cookie信息。可以使用request.cookies.get('cookie_name')来获取特定cookie的值。
    
request.headers  # 请求头
# 用于获取客户端请求的HTTP头信息。可以使用request.headers.get('header_name')来获取特定头字段的值。
    
request.path  # 不带域名, 请求路径如: /index
# 获取当前请求的路径,不包含域名部分。例如,对于URL example.com/index,request.path 的值为 /index。
    
request.full_path  # 不带域名, 带参数的请求路径
# 获取当前请求的路径,包含域名和参数部分。例如,对于URL example.com/index?name=John,request.full_path 的值为 /index?name=John。

request.url           #带域名带参数的请求路径
# 获取当前请求的完整URL,包括域名和参数。例如,http://example.com/index?name=John。
        
request.base_url      #带域名请求路径
# 获取当前请求的URL,不包含参数部分。例如,http://example.com/index。
        
request.url_root      #域名
# 获取当前请求的域名部分。例如,http://example.com。
            
request.files # 获取上传文件
obj = request.files['the_file_name']
obj.save('/var/www/uploads/' + secure_filename(filename))
# 上传文件<input type="file" name="file">
# 用于获取客户端上传的文件。可以使用request.files['file_field_name']来访问上传的文件对象。上传的文件可以使用.save()方法保存到指定的路径。

  响应

    # 四种响应方式
    return "字符串" # 直接返回字符串
    return render_template('html模板路径',**{})# 返回HTML模板
    return redirect('/index.html') # 跳转页面
    return jsonify({'k1':'v1'})  # 返回json数据

	# 更新响应体参数
    response = make_response(render_template('index.html'))
    response.delete_cookie('key')
    response.set_cookie('key', 'value')
    response.headers['X-Something'] = 'A value'
   return response
    """
    1. 通过调用make_response函数,创建一个响应对象,并将渲染后的index.html模板作为响应的内容。
    2. 用delete_cookie方法从响应对象中删除名为 'key' 的cookie。这将告诉客户端删除该cookie。
    3. 使用set_cookie方法向响应对象中设置一个名为 'key' 的cookie,并将其值设置为 'value'。
    4 通过修改headers属性,向响应中添加一个名为 'X-Something' 的自定义头,并将其值设置为 'A value'
    """

Flask的配置文件

from flask import Flask

app = Flask(__name__)

# 配置文件
# app.debug = True
# app.secret_key = '123123'

# 以字典的形式
# app.config['DEBUG'] = True

# 以文件的方式
# app.config.from_pyfile('settings.py')

# 以类的形式(推荐使用, 好比: 上线和线下所用的配置文件不同)
# 创建一个配置类
class DevelopmentConfig:
    DEBUG = True
    SECRET_KEY = 'your_secret_key'

# 使用 app.config.from_object 加载配置
app.config.from_object(DevelopmentConfig)


@app.route('/login')
def login():
    print("hello world")
    return 'ok'


if __name__ == '__main__':
    app.run()

各类配置

# 是否开启 Debug 模式
DEBUG = False

# 是否开启测试模式
TESTING = False

# 异常是否传递给上层应用
PROPAGATE_EXCEPTIONS = None

# 异常时上下文是否保留
PRESERVE_CONTEXT_ON_EXCEPTION = None

# 密钥(用于会话等加密)
# SECRET_KEY = None

# 会话的生命周期
# PERMANENT_SESSION_LIFETIME = timedelta(days=31)

# 是否启用 X-Sendfile 响应头
USE_X_SENDFILE = False

# 日志器名称
# LOGGER_NAME = None

# 请求日志处理策略
# LOGGER_HANDLER_POLICY = 'always'

# 服务器名称
# SERVER_NAME = None

# 应用程序根目录
# APPLICATION_ROOT = None

# 会话的 Cookie 名称
SESSION_COOKIE_NAME = 'session'

# 会话的 Cookie 域名
SESSION_COOKIE_DOMAIN = None

# 会话的 Cookie 路径
SESSION_COOKIE_PATH = None

# 会话的 Cookie 是否只能通过 HTTP 访问
SESSION_COOKIE_HTTPONLY = True

# 会话的 Cookie 是否启用安全标志(HTTPS)
SESSION_COOKIE_SECURE = False

# 每个请求是否刷新会话
SESSION_REFRESH_EACH_REQUEST = True

# 最大接受的请求体大小
# MAX_CONTENT_LENGTH = None

# 静态文件的缓存时间
# SEND_FILE_MAX_AGE_DEFAULT = timedelta(hours=12)

# 是否捕获损坏的请求错误
TRAP_BAD_REQUEST_ERRORS = False

# 是否捕获 HTTP 异常
TRAP_HTTP_EXCEPTIONS = False

# 是否解释模板加载
EXPLAIN_TEMPLATE_LOADING = False

# 首选 URL 方案
PREFERRED_URL_SCHEME = 'http'

# JSON 是否使用 ASCII 编码
JSON_AS_ASCII = True

# JSON 是否按键排序
JSON_SORT_KEYS = True

# JSON 是否格式化后输出
JSONIFY_PRETTYPRINT_REGULAR = True

# JSON 的 MIME 类型
JSONIFY_MIMETYPE = 'application/json'

# 模板是否自动重新加载
# TEMPLATES_AUTO_RELOAD = None

Flask闪现

闪现: 可用于记录和获取日志

  1. 若是要用flash就必须设置app.secret_key = ''   2. 日志数据只能获取一次,在取就没有了   3. 可以通过 flash('普通讯息',category="info"),对信息作分类   4. get_flashed_messages(with_categories=True,category_filter=("error",)),with_categories以键值对的形式获取   咱们设置闪现,category_filter=("error",)进行分类信息的过滤前端

from flask import Flask, flash, get_flashed_messages

app = Flask(__name__)
app.debug = True
app.secret_key = 'abcdefg'
'''
secret_key随便定义一个字符串并不是一个好的做法。为了确保会话数据的安全性,应该使用足够安全和复杂的字符串。可以使用随机字符串生成工具来生成一个随机的密钥,或者使用诸如 UUID、哈希函数等机制来生成一个唯一的密钥。
'''


@app.route('/index')
def index():
    # flash(message, category)
    flash("超时错误", category="error")
    flash('普通讯息', category="info")
    return ""


@app.route('/inner')
def inner():
    # 需要先运行index路由获取信息
    # with_categories=False 表示只显示信息, 不显示分类。 category_filter 代表获取信息类型
    data = get_flashed_messages(with_categories=False, category_filter=("error", "info"))
    data1 = get_flashed_messages(with_categories=True, category_filter=("error", "info"))
    print(data)
    print(data1)
    return ""


if __name__ == '__main__':
    app.run()

Flask表单处理

Flask-WTF是Flask中用于处理Web表单的扩展库。它基于WTF Python,一个处理表单数据的Python库。Flask-WTF还具有CSRF(跨站请求伪造)保护的功能。

让我们看一个简单的例子:

from flask import Flask, render_template
from flask_wtf import FlaskForm  # pip install flask-wtf
from wtforms import StringField
from wtforms.validators import InputRequired

app = Flask(__name__)
app.config['SECRET_KEY'] = 'abcd'


class MyForm(FlaskForm):
    name = StringField('Name', validators=[InputRequired()])


@app.route('/', methods=['GET', 'POST'])
def submit():
    form = MyForm()
    if form.validate_on_submit():
        name = form.name.data
        return f'Hello, {name}!'
    return render_template('hello.html', form=form)


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

validators=[InputRequired()]是在 Flask-WTF 表单中使用的验证器之一,它表示在验证输入时要求字段的值不能为空。

在这个例子中,我们定义了一个表单类MyForm,包含一个name字段。然后,我们在submit路由中创建了一个该类的实例,并检查表单是否通过验证。如果表单有效,我们就返回一条欢迎信息;否则,我们就渲染一个表单模板。

<!-- submit.html -->
<!DOCTYPE html>
<html lang="">
<head>
    <title>Submit Form</title>
</head>
<body>
    <h1>Submit Form</h1>
    <form action="{{ url_for('submit') }}" method="POST">
        {{ form.hidden_tag() }}
        <p>
            {{ form.name.label }} <br>
            {{ form.name(size=20) }} <br>
            {% for error in form.name.errors %}
                <span style="color: red;">{{ error }}</span>
            {% endfor %}
        </p>
        <input type="submit" value="Submit">
    </form>
</body>
</html>
  • {{ url_for('submit') }}:这是一个动态生成的 URL,它将表单提交到submit视图函数。url_for()函数会根据给定的视图函数名称生成对应的 URL。在这种情况下,它会生成一个指向submit视图函数的 URL,用于处理表单的提交。

  • {{ form.hidden_tag() }}:这是一个 Flask-WTF 表单生成的隐藏字段,用于防止跨站请求伪造(CSRF)攻击。在提交表单时,这个隐藏字段会被包含在表单数据中。

  • {{ form.name.label }}:这是表单字段name的标签。form.name表示这个字段在生成的表单中的位置。

  • {{ form.name(size=20) }}:这是表单字段name的输入框,其中name是输入框的名称,size是输入框的大小设置。在这个例子中,name字段的输入框大小被设置为20。

  • {% for error in form.name.errors %} 和 {{ error }}:这是一个用于迭代显示验证错误的循环。form.name.errors返回一个列表,其中包含了针对name字段的验证错误消息。该代码块将循环遍历错误列表,并对每个错误以红色文本的形式显示出来。

Flask蓝图

Flask的蓝图功能让我们能够组织更大、更复杂的应用程序。你可以将蓝图视为Flask应用程序的一个子集,它可以拥有自己的路由、模板和静态文件。

下面是一个简单的例子:app.py:

from flask import Flask
from blueprints.page import simple_page

app = Flask(__name__)
app.register_blueprint(simple_page)

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

blueprints/page.py:

from flask import Blueprint

simple_page = Blueprint('simple_page', __name__)

@simple_page.route('/<page>')
def show(page):
    return f'Page {page}'

蓝图的一个主要作用是将不同功能的代码组织到不同的文件中,以实现功能的模块化和路由函数的区分。

通过使用蓝图,你可以将不同的功能模块拆分到不同的文件中,比如将用户认证相关的代码放在一个文件,将文章管理相关的代码放在另一个文件。这样做的好处是可以使代码更加结构化,便于管理和维护。

Flask错误处理

Flask允许我们自定义错误处理函数,当特定的HTTP错误发生时,我们可以返回自定义的响应。以下是如何为404错误定义自定义处理函数的示例:

@app.errorhandler(404)
def page_not_found(error):
    return 'This page does not exist', 404

在这个例子中,我们使用app.errorhandler装饰器注册一个新的错误处理函数。当404错误发生时,它将返回一个自定义的错误消息。

Flask请求钩子

Flask提供了几个装饰器,我们可以使用它们来注册在处理请求的不同阶段调用的函数。这些装饰器包括before_first_requestbefore_requestafter_requestteardown_request

@app.before_first_request
def before_first_request():
    print("第一次请求")

@app.before_request
def before_request():
    print("开始请求")

@app.after_request
def after(response):
    print("请求之后")
    return response

# 有没有异常都会执行该函数, 没有e为None, 有e为错误信息
@app.teardown_request
def tear(e):
    print(e)

在以上例子中,装饰器的函数将在每个请求时执行。

Flask 中间键

在 Flask 中,中间件是对 WSGI 规范的实现,用于在请求被处理之前和之后执行一些额外的操作。中间件可以用于修改请求或响应、记录日志、执行身份验证等

from flask import Flask

app = Flask(__name__)
app.debug = True


class MyMiddleware:

    def __init__(self, wsgi_app):
        self.wsgi_app = wsgi_app

    def __call__(self, environ, start_response):
        print('以前操作')
        res = self.wsgi_app(environ, start_response)
        print('以后操作')
        return res


app.wsgi_app = MyMiddleware(app.wsgi_app)


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


@app.route('/inner')
def inner():
    print('ok2')
    return "ok2"


if __name__ == '__main__':
    app.run()

Flask中的Cookies和Sessions

在Web开发中,我们常常需要存储用户的信息,例如用户的偏好设置或者登录状态。Flask提供了Cookies和Sessions两种方式来完成这个任务。

下面是如何在Flask中设置和读取cookie的例子:

@app.route('/set')
def setcookie():
    resp = make_response('Setting cookie!')
    resp.set_cookie('username', 'the username')
    return resp
    '''
    resp = make_response(render_template('index.html'))
    resp.set_cookie('username', 'John')
    return resp
    '''


@app.route('/get')
def getcookie():
    username = request.cookies.get('username')
    return 'The username is ' + username

在上述例子中,setcookie路由设置了一个cookie,名为usernamegetcookie路由读取并返回了这个cookie的值。

"""
session和cookie
app.session_interface这里面看
存session:
    1. 调用save_session,将咱们的session加密的val,读取配置文件['SESSION_COOKIE_NAME']获得key
    2. 将1种的key,val存储到cookies

取session;
    1. 获取request里面的cookies,获取里面key,这个key就是['SESSION_COOKIE_NAME'],值就是加密的值
    2. 对该值进行解密
"""
from flask import Flask, session

app = Flask(__name__)
app.debug = True
# 在浏览器存储的key名字
app.config['SESSION_COOKIE_NAME'] = 'session'
# 秘钥
app.secret_key = 'ahsodhfb'

# 存
@app.route('/index')
def index():
    session['hello'] = 'world'
    return 'ok'

# 取
@app.route('/login')
def login():
    print(session.get('hello'))
    return 'I am fine'

if __name__ == '__main__':
    app.run()

在 Flask 中,你可以通过设置 Cookie 和 Session 的过期时间来定义它们的时限。

设置 Cookie 的时限: 通过 set_cookie() 方法可以设置 Cookie 的过期时间。它接受一个可选的 expires 参数,用于指定 Cookie 的失效时间。expires 参数可以是一个 datetime 对象,表示具体的失效时间;也可以是一个字符串,表示相对于当前时间的时间间隔。如果不设置 expires 参数,默认情况下,Cookie 是会话性的,即在浏览器关闭时失效。

以下是一个示例,在设置 Cookie 时指定过期时间:

from flask import Flask, make_response, request
import datetime

app = Flask(__name__)

@app.route('/')
def index():
    resp = make_response('Hello, world!')
    expires = datetime.datetime.now() + datetime.timedelta(days=30)
    resp.set_cookie('username', 'John', expires=expires)
    return resp

if __name__ == '__main__':
    app.run()

在这个示例中,通过 expires 参数将 Cookie 的过期时间设置为当前时间加上 30 天。这样,浏览器在存储这个 Cookie 后,将会在 30 天后自动将其删除。

设置 Session 的时限: Flask 中的会话默认情况下是永久会话,即会持久保留在服务器端,直到手动删除或超过设定的失效时间。你可以通过设置 permanant_session_lifetime 属性来定义会话的过期时间。

以下是一个示例,在 Flask 应用中设置会话的过期时间为 2 小时:

from flask import Flask, session

app = Flask(__name__)
app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(hours=2)

@app.route('/')
def index():
    session.permanent = True  # 在会话中设置 permanent 属性为 True
    session['username'] = 'John'
    return 'Hello, world!'

if __name__ == '__main__':
    app.run()

在这个示例中,我们使用 app.config['PERMANENT_SESSION_LIFETIME'] 设置会话的过期时间为 2 小时。然后,在请求处理函数中,我们将会话的 permanent 属性设置为 True,表示这个会话是持久会话,将会根据设定的过期时间进行失效。如果不设置 permanent 属性,默认情况下会话是非持久的,即浏览器关闭时失效。

通过设置 Cookie 和 Session 的过期时间,可以根据需要控制它们的时限,使其在指定时间后失效,增加应用的安全性和用户体验。

转载自:https://juejin.cn/post/7287117489304469561
评论
请登录