Flask基础内容

Flask基础内容,第1张

文章目录
  • Flask 框架
    • 一、 简介
      • 1、 框架介绍
      • 2、 架构模式
      • 3、 环境搭建
    • 二、 第一个应用
    • 三、 框架语法
      • 1、 框架之配置
      • 2、 框架之路由
        • 2.1 添加路由
        • 2.2 反向生成
        • 2.3 路由系统
        • 2.4 路由参数
        • 2.5 添加装饰器
          • 2.5.1 FBV
          • 2.5.2 CBV
      • 3、 请求与响应
      • 4、 模板引擎
        • 1、 变量
        • 2、 继承
      • 5、 session
        • 5.1 源码分析
        • 5.2 基本使用
        • 5.3 过期时间
      • 6、 请求拓展
      • 7、 框架之闪现
      • 8、 中间件
      • 9、 蓝图
        • 9.1 分区式架构
          • 9.1.1 目录结构
          • 9.1.2 代码实现
          • 9.1.3 访问
        • 9.2 功能式架构
          • 9.2.1 目录结构
          • 9.2.2 代码实现
      • 10、 文件上传
    • 四、 上下文管理
      • 1、 Local对象
        • 1.1 `threading.local`
        • 1.2 基于函数
        • 1.3 基于对象
      • 2、 上下文管理阶段
      • 3、 g

Flask 框架 一、 简介 1、 框架介绍

Flask是一个基于Python并且依赖于Jinja2模板引擎和Werkzeug WSGI 服务的一个微型框架
WSGI :Web Server Gateway Interface(WEB服务网关接口),定义了使用python编写的web app与web server之间接口格式

其他类型框架:

  1. Django:比较“重”的框架,同时也是最出名的Python框架。包含了web开发中常用的功能、组件的框架(ORM、Session、Form、Admin、分页、中间件、信号、缓存、ContenType…),Django是走大而全的方向,最出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构、以及全功能的管理后台。

  2. Tornado:大特性就是异步非阻塞、原生支持WebSocket协议;

  3. Flask: 一个轻量级的基于 Python 的 Web 框架

  4. Bottle:是一个简单高效的遵循WSGI的微型python Web框架。说微型,是因为它只有一个文件,除Python标准库外,它不依赖于任何第三方模块。

2、 架构模式

Flask的架构模式-MTV

  1. 经典三层结构 :MVC模式
    • M :Models ,模型层,负责数据库建模
    • V :Views,视图层,用于处理用户显示的内容,如 :html
    • C :Controller,控制器,处理与用户交互的部分内容。处理用户的请求并给出响应
  2. python常用:MTV模式
    • M :Models ,模型层,负责数据库建模
    • T :Templates ,模板层,用于处理用户显示的内容,如:html
    • V :Views ,视图层,处理与用户交互的部分内容。处理用户的请求并给出响应
3、 环境搭建
  1. 安装

    pip install flask
    
  2. 创建工作目录

    mkdir first_dir  # 创建工作目录
    mkdir first_dir/static  # 创建存放图片、css等不需要动态生成的静态文件
    mkdir first_dir/templates  # 创建存放响应文本的模板文件夹
    touch first_dir/app.py  # 主程序
    
  3. app.py中添加

    from flask import Flask
    
    app = Flask(__name__)
    
    
    @app.route('/')  # Flask路由
    def hello_world():
        return 'Hello World!'
    
    
    if __name__ == '__main__':
        app.run()  # 运行网站
    

    主程序会默认访问templatesstatic文件夹,如果,存放web文件的文件夹名称不是这两个,那么要在实例化Flask路由时,声明

flask中文网:https://flask.net.cn/

如果对一些语法有疑问,可以自行访问官网去查看

二、 第一个应用

主程序代码

from flask import (Flask, render_template
, request, redirect, session)

app = Flask(__name__)  # 创建一个服务器
app.secret_key = "ashdjhfcasjcvbgjs"  # 设置盐,对session信息进行加密,随机字符串
app.debug = True  # 当文件保存时,flask服务就重启
USER_DICT = {
    "1": {"name": "李华", "age": 12},
    "2": {"name": "李虎", "age": 13},
}  # 假设这个为用户数据,其为从数据库中读取出来的


@app.route('/login', methods=["GET", "POST"])
def hello_world():
    if request.method == "GET":  # 如果请求方式为get请求
        return render_template("login.html")  # 对静态文件中的文件进行渲染
    user = request.form.get("user")  # 得到表单数据
    pwd = request.form.get("pwd")
    if user == "kun" and pwd == "123":  # 进行判断
        # 用户信息放入session中,默认放入浏览器的cookie中
        session["user_info"] = user
        return redirect("/index")  # 进行重定向
    return render_template("login.html", msg="账号或密码错误,登录失败")  # 如果登录失败,将失败信息传入前端页面中


@app.route("/detail")
def detail():
    user_info = session.get("user_info")
    if not user_info:  # 判断是否登录
        return redirect("/login")  # 如果没有登录,重定向到登录界面
    uid = request.args.get("uid")  # 获取传入的参数
    info = USER_DICT.get(uid)  # 获取人员信息
    return render_template("detail.html", info=info)  # 进行页面的渲染


@app.route("/index")
def index():
    user_info = session.get("user_info")
    if not user_info:  # 如果没有用户信息,则返回登录页面
        return redirect("/login")
    return render_template("index.html", user_dict=USER_DICT)


@app.route("/loginout")
def loginout():
    del session["user_info"]  # 删除cookies信息,进行注销 *** 作
    return redirect("/login")  # 重定向到登录页面


@app.route("/")
def red():  # 如果直接访问的话,默认跳转到登录界面
    return redirect("/index")  # 进行url的跳转


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

代码详情在:【https://github.com/liuzhongkun1/flask_/tree/main/firstFlask】

三、 框架语法

参考文档:【https://www.cnblogs.com/wupeiqi/asticles/7552008.html】

1、 框架之配置
# flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
{
    'DEBUG': get_debug_flag(default=False),  # 是否开启Debug模式
    'TESTING': False,  # 是否开启测试模式
    'PROPAGATE_EXCEPTIONS': None,                          
    'PRESERVE_CONTEXT_ON_EXCEPTION': None,
    'SECRET_KEY': None,
    'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
    'USE_X_SENDFILE': False,
    'LOGGER_NAME': None,
    'LOGGER_HANDLER_POLICY': 'always',
    'SERVER_NAME': None,
    'APPLICATION_ROOT': None,
    'SESSION_COOKIE_NAME': 'session',
    'SESSION_COOKIE_DOMAIN': None,
    'SESSION_COOKIE_PATH': None,
    'SESSION_COOKIE_HTTPONLY': True,
    '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,
    'TRAP_HTTP_EXCEPTIONS': False,
    'EXPLAIN_TEMPLATE_LOADING': False,
    'PREFERRED_URL_SCHEME': 'http',
    'JSON_AS_ASCII':  True,
    'JSON_SORT_KEYS': True,
    'JSONIFY_PRETTYPRINT_REGULAR': True,
    'JSONIFY_MIMETYPE': 'application/json',
    'TEMPLATES_AUTO_RELOAD': None,
}
 
# 方式一:
app.config['DEBUG'] = True  # PS: 由于Config对象本质上是字典,所以还可以使用app.config.update(...)

# 方式二:
app.config.from_pyfile("python文件名称")
"""
        如:
            settings.py
                DEBUG = True
 
            app.config.from_pyfile("settings.py")
""" 
app.config.from_envvar("环境变量名称")  # 环境变量的值为python文件名称名称,内部调用from_pyfile方法

app.config.from_json("json文件名称")  # JSON文件名称,必须是json格式,因为内部会执行json.loads

app.config.from_mapping({'DEBUG':True})  # 字典格式

app.config.from_object("python类或类的路径")  # 传入一个类
"""
如:
app.config.from_object('pro_flask.settings.TestingConfig')
        settings.py
            class Config(object):
                DEBUG = False
                TESTING = False
                DATABASE_URI = 'sqlite://:memory:'
                
            class ProductionConfig(Config):
                DATABASE_URI = 'mysql://user@localhost/foo'
 
            class DevelopmentConfig(Config):
                DEBUG = True
 
            class TestingConfig(Config):
                TESTING = True
 
        PS: 从sys.path中已经存在路径开始写
    PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录
"""

具体的配置参数请通过官方文档获取

2、 框架之路由 2.1 添加路由
# 第一种
@app.route('/')
def hello_world():
    return 'Hello World!'


# 第二种
def index():
    return "index"

app.add_url_rule("/index", None, index)
2.2 反向生成
from flask import Flask, url_for, redirect

app = Flask(__name__)


@app.route('/')
def hello_world():
    index_ = url_for("i")  # 返回i对应的路由
    print(index_)  # 可以进行重定向
    return redirect(index_)  # 进行重定向


@app.route("/index/asdhjaskdg/sad", endpoint="i")  # endpoint默认为函数名
def index():
    return "index"


if __name__ == '__main__':
    app.run()
2.3 路由系统
  • @app.route('/user/'):传递字符串类型的数据
  • @app.route('/post/'):传递整型数据
  • @app.route('/post/'):传递浮点类型数据
  • @app.route('/post/'):传递路径
  • @app.route('/'):传递自定义数据类型
from flask import Flask, url_for
from werkzeug.routing import BaseConverter

app = Flask(import_name=__name__)

# 1.定义自己的转换器
class RegexConverter(BaseConverter):
	
     # map是固定的参数,将整个列表进行带入,regex是写入的参数,添加进新的转换器类型
    def __init__(self, map, regex):
        # 调用父类的初始化方法
        super(RegexConverter, self).__init__(map)
        self.regex = regex

    def to_python(self, value):
        # 路由匹配时,匹配成功后传递给视图函数中参数的值
        return int(value)

    def to_url(self, value):
        # 使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
        val = super(RegexConverter, self).to_url(value)
        print(val)
        return val


# 2.将自定义的转换器添加到flask的应用中
app.url_map.converters['regex'] = RegexConverter


@app.route('/index/')
def index(nid):
    print(url_for('index', nid='888'))
    return 'Index'


if __name__ == '__main__':
    print(app.url_map)  # 查看路由信息
    app.run()
2.4 路由参数
  1. rule

    • url规则
  2. voew_func

    • 视图名称
  3. defaults=None

    • 默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
  4. endpoint=None

    • 名称,用于反向生成URL,即: url_for('名称')
  5. methods=None

    • 允许请求的方式,默认为GET,可以是可迭代对象,如methods=["GET", "POST"]
  6. strict_slashed=None

    • url最后的\是否有严格的要求,如

      @app.route('/index',strict_slashes=False)  # 访问 http://www.xx.com/index/ 或 http://www.xx.com/index均可
      @app.route('/index',strict_slashes=True)  # 仅访问 http://www.xx.com/index 
      
  7. redirect_to=None

    • 重定向到指定地址

      from flask import Flask
      
      app = Flask(import_name=__name__)
      
      
      @app.route('/index', redirect_to='/home')  # 或 redirect_to=home
      def func():
          return "index"
      
      
      @app.route('/home')
      def home():
          return "home"
      
      if __name__ == '__main__':
          app.run()
      
  8. subdomain=None

    • 匹配子域名

      from flask import Flask
      
      app = Flask(import_name=__name__)
      
      
      @app.route("/", subdomain="")  # 注意,这里要使用域名才能使用
      def main(username):
          print(username)
          return "hello"
      
      if __name__ == '__main__':
          app.run()
      
2.5 添加装饰器 2.5.1 FBV
from flask import Flask
from functools import wraps


def outer(func):
    @wraps(func)  # 使得内层函数的函数名为传入的函数的函数名,反正重名
    def inner(*args, **kwargs):
        print("装饰器运行")
        return func(*args, **kwargs)

    return inner


app = Flask(import_name=__name__)


@app.route('/')
@outer  # 这个装饰器可以进行登录验证
def main():
    return "hello"


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

如果要给框架另增加装饰器,一定要在路由装饰器的下面添加

2.5.2 CBV
from flask import Flask, views
from functools import wraps


def decorator(func):
    @wraps(func)
    def inner(*args, **kwargs):
        print("装饰器运行")
        return func(*args, **kwargs)

    return inner


app = Flask(import_name=__name__)


# CBV 一
class IndexView(views.View):
    methods = ["GET", "POST"]  # 请求方式
    decorators = [decorator, ]  # 添加装饰器,可以添加多个

    # dispatch_request这个名字是固定的
    def dispatch_request(self):
        return "index"


app.add_url_rule("/index_cbv", view_func=IndexView.as_view(name="index_c"))  # 这里的name相当于endpoint


# CBV 二
class IndexView2(views.MethodView):
    '''
    在views.MethodView中,相较于views.View,函数dispatch_request,已经在代码中写好了,反射getattr
    '''
    methods = ["GET", "POST"]
    decorators = [decorator, ]

    def get(self):
        return "get"  # get请求返回的值

    def post(self):
        return "post"  # post请求返回的值


app.add_url_rule("/index_cbv2", view_func=IndexView2.as_view(name="index_c2"))  # 这里的name相当于endpoint

if __name__ == '__main__':
    app.run()
3、 请求与响应
from flask import Flask, request, render_template, redirect, jsonify\
    , make_response  # 返回响应头

app = Flask(__name__)


@app.route('/')
def index():
    """请求相关信息"""
    # request.method
    # request.args
    # request.form
    # request.values
    # request.cookies
    # request.headers
    # request.path
    # request.files
    # obj = request.files['the_file_name']
    # obj.save('/var/www/uploads/' + secure_filename(f.filename))
    """以上的是常用的"""
    # request.full_path
    # request.script_root
    # request.url
    # request.base_url
    # request.url_root
    # request.host_url
    # request.host

    """响应相关"""
    """
    响应头的使用
    response = make_response(render_template('index.html'))  # 创建响应数据
    print(type(response))
    response.delete_cookie('key')  # 删除cookie
    response.set_cookie('key', 'value')  # 设置cookie
    response.headers['X-Something'] = 'A value'
    return response
    """
    return "hello world"  # 可以使用json.dumps({}) / jsonify({}) 返回JSON数据
    # return render_template("index.html", n1=123)  # 渲染静态文件,第二个参数可以是字典解包,或者等号传参,传递给前端页面
    # return redirect("/index")  # 重定向


if __name__ == '__main__':
    app.run()
4、 模板引擎 1、 变量

index.html里面的内容

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>indextitle>
head>
<body>
<h5>{{ k1 }}h5>  
<h4>{{ k2[0] }} {{ k2[1] }}h4>  
<h5>匿名函数运行的结果为:{{ k3("pwd") | safe }}h5>  
body>
html>

app.py 里面的内容

from flask import Flask, render_template, Markup


app = Flask(__name__)


def input_(value):
    # 生成input标签
    return Markup("" % value)  # Markup 的功能和|safe一样,使得html内容可以渲染出来,关闭对文本信息的转义,其为过滤器


@app.route('/')
def index():
    context = {
        "k1": 123,
        "k2": [11, 12, 13],
        "k3": lambda x: input_(x),
    }
    return render_template("index.html", **context)


if __name__ == '__main__':
    app.run()
2、 继承

parent.html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>父类title>
head>
<body>
<div>头部div>
<div>
    {% block content %}
    	
    {% endblock %}
div>
<div>尾部div>

body>
html>

son.html

{% extends "parent.html" %}  
{% block content %}  
<h5>{{ k1 }}h5>
<h4>{{ k2[0] }} {{ k2[1] }}h4>
<h5>匿名函数运行的结果为:{{ k3("pwd") | safe }}h5>

{% endblock %}

支持多继承

更多的模板编程语法:【https://blog.csdn.net/u013075024/article/details/121870876】

5、 session

除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥

字典中拥有的方法,session就拥有

5.1 源码分析

app.run()运行前,会运行app.__call__,然后返回app.wsgi_app(environ, start_response),然后通过ctx = Request_Context(app, environ)创建一个对象,在这时,使用ctx.push()方法,传入session,当请求结束后,将session序列化以后,返回到cookie里面,并且调用ctx.auto_pop(error)方法,删除ctx


"""当发起请求时"""
session = session_interface.open_session(self.app, self.request)  # 给session赋值
session = SecureCookieSessionInterface().open_session(self.app, self.request) 
session = CallbackDict()  # 其为一个自定义字典对象

----------------------------------------------------------------

"""当请求结束时"""
self.session_interface.save_session(self, ctx.session, response)  # 将session保存到response中
SecureCookieSessionInterface().save_session(self, ctx.session, response)
# 最后在SecureCookieSessionInterface()中
val = self.get_signing_serializer(app).dumps(dict(session))  # 将session序列化
response.set_cookie(
            name,  # self.get_cookie_name(app)
            val,  # type: ignore
            expires=expires,  # self.get_expiration_time(app, session)
            httponly=httponly,  # self.get_cookie_httponly(app)
            domain=domain,  # self.get_cookie_domain(app)
            path=path,  # self.get_cookie_path(app)
            secure=secure,  # self.get_cookie_secure(app)
            samesite=samesite,  # self.get_cookie_samesite(app)
       )
5.2 基本使用
from flask import Flask, session, escape
import os

app = Flask(__name__)
app.secret_key = os.urandom(32)  # 设置一个密钥,随机的32位字符串


@app.route('/login/')
def index(username):
    session["name"] = username  # __setitem__ 设置session
    return "index %s" % escape(username)  # 使用escape对信息进行转义处理,防止恶意攻击,使用Markup可以进行反转义


@app.route('/verify')
def main():
    a = session.get("name")  # __getitem__  一般使用get方法获取值,因为不存在的话不会报错
    print(a)
    return "main"


@app.route("/delete")
def delete():
    session.pop("name", None)  # 删除指定的键
    return "删除成功"


@app.route("/clear")
def clear():
    session.clear()  # 清空session信息
    return "清空成功"


if __name__ == '__main__':
    app.run()
5.3 过期时间

如果没有指定session的过期时间,那么默认是浏览器关闭后就自动结束。session.permanent = Trueflask下则可以将有效期延长至一个月。下面有方法可以配置具体多少天的有效期:

  • 如果没有指定session的过期时间,那么默认是浏览器关闭后就自动结束
  • 如果设置了sessionpermanent属性为True,那么过期时间是31天
  • 可以通过给app.config设置PERMANENT_SESSION_LIFETIME来更改过期时间,这个值的数据类型是datetime.timedelay类型
from flask import Flask
import os
from datetime import timedelta

app = Flask(__name__)
app.secret_key = os.urandom(32)  # 设置一个密钥,随机的32位字符串
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)  # 配置7天有效 

session还可以结合数据库和类等自己定义哦~~~

6、 请求拓展
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, Request, render_template

app = Flask(__name__, template_folder='templates')
app.debug = True


@app.before_first_request
# 只会执行一次,第一个访问者执行此函数
def before_first_request1():
    print('before_first_request1')


@app.before_request
def before_request1():
    Request.nnn = 123
    print('before_request1')


@app.before_request
# 在请求发送前
def before_request2():
    print('before_request2')


@app.after_request
# 在请求发送后的响应,注意,必须要接收响应,并且返回响应
def after_request1(response):
    print('before_request1', response)
    return response


@app.errorhandler(404)
# 使用abort(404)抛出异常
# 异常处理,如果异常代码是404的话
def page_not_found(error):
    return 'This page does not exist', 404


@app.template_global()
# 创建函数为Flask全局函数
def sb(a1, a2):
    return a1 + a2


@app.template_filter('md')
# 定义一个以模板过滤器作为装饰器的函数,函数传入参数txt,即将内容转换为md类型的文件
# 如 {{ "# title" | md }}  # 将文本信息传入过滤器中,转换为md文本
def markdown_to_html(txt):
    from markdown import markdown
    return markdown(txt)


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


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

那装饰器函数可以添加多个,执行顺序是从上到下

7、 框架之闪现
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import os

from flask import Flask, flash, get_flashed_messages  # 其为基于session来实现的

app = Flask(__name__, template_folder='templates')
app.debug = True
app.secret_key = os.urandom(32)


@app.route('/')
def login():
    flash("hello", category="x1")  # x1给数据分类,也可以不分类
    return "你好呀"


@app.route('/get_flash')
def get_flash():
    data = get_flashed_messages(category_filter=["x1"])  # 只拿想x1类型的数据,该数据只能访问一次,访问后就被删除
    return  str(data)


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

闪现的数据只能访问一次,访问一次后就被删除了

8、 中间件
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import os

from flask import Flask

app = Flask(__name__, template_folder='templates')
app.debug = True
app.secret_key = os.urandom(32)


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


class MiddleWare:
    def __init__(self, old_wsgi_app):
        self.old_wsgi_app = old_wsgi_app

    def __call__(self, environ, start_response):
        """
        每次用户请求到来时
        :param environ: A WSGI environment 原生的http请求
        :param start_response: A callable accepting a status code, a list of headers, and an optional exception context to start the response
        :return: wsgi_app
        """
        print("执行前的 *** 作")
        obj = self.old_wsgi_app(environ, start_response)
        print("执行后的 *** 作")
        return obj


if __name__ == '__main__':
    app.wsgi_app = MiddleWare(app.wsgi_app)
    app.run()
    """
    1. 执行app.__call__
    2. 再调用app.wsgi_app方法
    其相当于装饰器的使用方法
    """

闪现和中间件的使用场景不多

9、 蓝图 9.1 分区式架构 9.1.1 目录结构

首先我们创建一个目录结构

blue-example/
├── app.py
├── __init__.py
├── admin
│   ├── __init__.py
|	├── static
|	├── templates
│   └── views.py
└── user
    ├── __init__.py
	├── static
	├── templates
	└── views.py

实现用户登录和管理员登录,同时将业务分离

9.1.2 代码实现

app.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask
from admin import admin
from web import web

app = Flask(__name__)
app.debug = True

app.register_blueprint(admin, url_prefix='/admin')
app.register_blueprint(web, url_prefix="/web")

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

url_prefix:在蓝图上注册的路由URL自动被加上了这个前缀,这个可以保证在多个蓝图中使用相同的URL规则而不会最终引起冲突,只要在注册蓝图时将不同的蓝图挂接到不同的自路径即可。默认为/

admin文件夹中

__init__.py中写入

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Blueprint

admin = Blueprint(
    'admin',
    __name__,
    template_folder='templates',
    static_folder='static'
)
from . import views  # 将视图中的代码导入init模块中

view.py中写入

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from . import admin  # 从init文件中导入admin蓝图


@admin.route('/index')  # 创建路由
def index():
    return 'Admin.Index'

user文件夹中写入的内容和admin文件夹的类似

__init__.py文件创建蓝图对象

view.py实现路由,在导入__init__.py中进行初始化

9.1.3 访问
127.0.0.1:5000/admin/index 访问的是admin文件夹里面的路由
127.0.0.1:5000/user/index 访问的是user文件夹里面的路由
9.2 功能式架构 9.2.1 目录结构

功能式架构的目录结构

blue-example/
├── __init__.py
├── app.py
├── statics
└── templates
    ├── user
	└── admin
└── views
    ├── __init__.py
	├── user.py
	└── admin.py
9.2.2 代码实现

app.py

from flask import Flask

app = Flask(__name__, template_folder='templates', static_folder='statics', static_url_path='/static')

from views.admin import admin
from views.user import user

app.register_blueprint(admin, url_prefix='/admin')
app.register_blueprint(user, url_prefix='/user')

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

static_url_path:端访问资源文件的前缀目录。默认是/static,就是前端必须这样访问:src="/static/img/mylogo.jpg" />
我们改成 ’ ',就可以这样访问了: 。就达到前端从根目录访问的目的了

同时,使用url_for("static", filename="xxx.png")时,要添加static_url_path="/static"

admin.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Blueprint
from flask import render_template

admin = Blueprint('admin', __name__)


@admin.route('/login.html', methods=['GET', "POST"])
def login():
    return render_template('login.html')

访问方式是:127.0.0.1:5000/admin/login.html

user.py中的内容类似

两种架构并没有好坏之分,可以根据具体的情况来确定方案

10、 文件上传

在 Flask 中处理文件上传非常简单。它需要一个 HTML 表单,其 enctype 属性设置为“multipart/form-data”,将文件发布到 URL

URL 处理程序从 request.files[] 对象中提取文件,并将其保存到所需的位置

同时,要给app添加的配置

app.config['UPLOAD_FOLDER'] # 定义上传文件夹的路径 
app.config['MAX_CONTENT_LENGTH']  # 指定要上传的文件的最大大小(以字节为单位)

如,一个上传文件的文件,upload.html

<html>
<head>
  <title>File Uploadtitle>
head>
<body>
    <form action="http://localhost:5000/uploader" method="POST" enctype="multipart/form-data">
        <input type="file" name="file"  />
        <input type="submit" value="提交" />
    form>
body>
html>

在主程序中

from flask import Flask, render_template, request, url_for, redirect
from werkzeug.utils import secure_filename  # 过滤文件的名称,反正被攻击
import os

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'upload/'  # 设置上传的文件目录

@app.route('/upload')
def upload_file():
    return render_template('upload.html')  # 对文本信息进行渲染

@app.route('/uploader', methods=['GET', 'POST'])
def uploader():
    if request.method == 'POST':  # 如果为post请求,则为发送文件
        f = request.files['file']  # 获取传递过来的文件
        print(f.filename)  # 打印文件
        f.save(os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(f.filename)))
        return 'file uploaded successfully'
    else:
        return redirect(url_for("upload_file"))  # 对GET请求进行重定向

if __name__ == '__main__':
    app.run(debug=True)
四、 上下文管理

详细介绍:【https://www.cnblogs.com/zhaopanpan/articles/9457343.html】

1、 Local对象 1.1 threading.local
from threading import local, Thread
from time import sleep

local_ = local()


def task(i):
    # 字典,键为线程的ident作为唯一标识
    local_.val = i
    sleep(2)
    print(local_.val)


for i in range(10):
    t = Thread(target=task, args=(i,))
    t.start()

作用:

  • 为每一个线程开辟一块空间进行数据存储

问题:

  • 我们自己通过字典创建一个类似于threading.local的东西
1.2 基于函数
from threading import Thread, get_ident
from time import sleep

storage = {}


def set(k, v):
    ident = get_ident()
    if ident in storage.keys():
        storage[ident][k] = v  # 给ident对应的值设置为{k, v}
    else:
        storage[ident] = {k: v}  # 创建ident键,并将值设置为{k, v}


def get(k):
    ident = get_ident()
    try:
        # 如果键不存在,则返回None
        val = storage[ident][k]
        return val
    except KeyError:
        return None


def task(arg):
    set("val", arg)
    sleep(2)
    print(get("val"))


for i in range(10):
    t = Thread(target=task, args=(i,))
    t.start()
1.3 基于对象
from threading import Thread
from time import sleep
try:
    from greenlet import getcurrent as get_ident  # 获取当前协程的唯一标识
except ImportError:
    from threading import get_ident  # 如果无法使用协程,那么继续使用线程的唯一标识
# 使其为每一个协程(线程)开辟一块空间进行数据存储


class MyLocal:
    def __init__(self):
        # data存储一个字典
        # self.data = {}  # 会触发__setattr__方法
        object.__setattr__(self, "data", {})  # 调用父类中的__setattr__方法,避免重复调用

    def __getattr__(self, k):
        # 实现local.key方法
        ident = get_ident()
        try:
            # 如果键不存在,则返回None
            val = self.data[ident][k]
            return val
        except KeyError:
            return None

    def __setattr__(self, key, value):
        # 实现local.key = value
        ident = get_ident()
        if ident in self.data:
            self.data[ident][key] = value
        else:
            self.data[ident] = {key: value}


local = MyLocal()


def task(arg):
    local.val = arg  # __setattr__
    sleep(2)
    print(local.val)  # __getattr__


for i in range(10):
    t = Thread(target=task, args=(i,))
    t.start()

print(local.data)
2、 上下文管理阶段

1. 第一阶段:将ctx(request, session)放到Local对象里面
	- ctx = RequestContext()
2. 第二阶段:视图函数导入:
	- request/session
3. 第三阶段:请求处理完毕
	- 获取session并保存到cookie
	- 将ctx删除
3、 g

与请求上下文类似,当请求进来时,先实例化一个AppContext对象app_ctx,在实例化的过程中,提供了两个有用的属性,一个是app,一个是gself.app就是传入的全局的app对象,self.g是一个全局的存储值的对象。接着将这个app_ctx存放到LocalStack()

像数据库配置这样重要的信息挂载在app对象上,一些用户相关的数据,就可以挂载在g对象上,这样就不需要在函数里一层层传递

from flask import Flask, g

app = Flask(__name__)


@app.before_request
def auth_demo():
    g.val = 123


@app.route('/')
def index():
    print(g.val)
    return "Hello World"


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

g对象的生命周期和当前的请求对应,当请求结束时,g对象被销毁

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/922016.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存