【1.0】flask框架之初识

【一】Flask框架引入

【1】Python界的web框架

(1)Django:

  • Django是一个高级的Python Web框架,它注重快速开发和代码复用。
  • 它提供了许多内置功能和模块,包括ORM(对象关系映射),表单处理,用户认证,会话管理等。
  • Django采用了MTV(模型-模板-视图)的设计模式,使得开发人员可以更加专注于业务逻辑而不是底层细节。
  • Django适合用于构建大型、复杂的Web应用程序,例如公司内部项目。

(2)Flask:

  • Flask是一个轻量级的Python Web框架,它以简洁灵活为特点。

  • Flask并没有像Django那样提供大量内置功能,而是通过使用扩展包来添加功能。

  • 这使得开发者可以按需选择所需的功能,从而保持代码精简。

  • Flask适合用于构建中小型的Web应用程序或者快速原型开发。由于其灵活性和丰富的第三方插件生态系统,Flask在社区中非常受欢迎。

(3)FastApi:

  • FastApi是一个现代、高性能的异步Python Web框架,它专注于构建API应用程序。

  • FastApi基于Python 3.6+的asyncio库,利用异步编程的优势来提供出色的性能。

  • 它具有自动化的请求和响应验证、强大的数据序列化和文档生成功能,特别适合用于构建前后端分离的接口。

  • FastApi的设计哲学是简洁明了,代码易于理解和维护。

(4)Sanic:

  • Sanic是另一个异步Python Web框架,它专注于高性能和低延迟。

  • 由于采用异步编程,Sanic能够处理大量并发请求,并具有出色的性能表现。

  • Sanic支持Python 3.6及以上版本,并提供了类似Flask的API接口,使用起来相对简单。

  • Sanic适合于构建需要处理大量请求和对响应时间敏感的应用程序。

(5)Tornado:

  • Tornado是一个使用Python编写的异步Web框架和异步网络库。
  • 它以其高性能和可扩展性而闻名。
  • Tornado采用了事件驱动的编程模型,利用非阻塞式I/O操作实现了并发处理。
  • Tornado的设计使得可以处理大量并发连接和高负载的情况,非常适合构建实时Web应用程序或需要处理大量长连接的应用程序。

(6)总结

  • Python界的Web框架有Django、Flask、FastApi、Sanic和Tornado等几种选择。
  • 选择合适的框架取决于项目的规模、复杂度、性能需求和开发者的喜好。
  • Django适合大型、复杂的项目,而Flask更适用于中小型项目和快速原型开发。
  • FastApi、Sanic和Tornado都是异步框架,适用于处理大量并发请求和对性能要求较高的应用场景。
  • fastapi简解
    • 高性能的异步Python Web框架
import time
# 引入 FastAPI 框架
from fastapi import FastAPI

# 实例化的到 FastAPI 对象
app = FastAPI()
@app.get('/')
async def index():
    time.sleep(3)
    return {'code': 100, 'msg': '成功'}

@app.get('/home')
async def home():
    time.sleep(2)
    return {'code': 100, 'msg': 'home'}

@app.get('/order')
async def home():
    time.sleep(2)
    return {'code': 100, 'msg': 'order'}
  • 如果是Django、flask,这种同步框架,会启动三个线程来处理这三个请求
  • 但是fastapi、sanic这种异步框架,会用一个线程来处理这三个请求
    • 异步框架(如FastAPI、Sanic和Tornado)使用单个线程来处理多个请求,并通过事件循环(Event Loop)和协程(Coroutine)机制实现并发处理。
    • 当一个请求中遇到IO等待时,框架会自动切换到其他请求去执行,从而减少了线程切换的开销,提高了性能和并发性能。

【二】Flask框架简单使用

【1】安装

  • 通过pip安装Flask框架。可以使用以下命令进行安装:
pip3 install flask

【2】简单使用

from flask import Flask
app = Flask(__name__)
@app.route('/', methods=['GET'])
def index():
    return 'hello world'
if __name__ == '__main__':
    app.run()
  • 在代码中,我们导入了Flask类,并创建了一个Flask对象,传入__name__作为应用程序的名称。
from flask import Flask
app = Flask(__name__)
  • Flask类的构造函数接受一个参数__name__,它会根据这个参数确定根目录的位置,方便在稍后的代码中定位资源文件等。

  • 接下来,我们使用@app.route装饰器来定义一个路由处理函数,即index()函数。装饰器会将URL路径"/"与该函数进行绑定,并指定支持的HTTP方法为GET。

@app.route('/', methods=['GET'])
def index():
    return 'hello world'
  • 在该函数中,我们简单地返回了一个字符串"hello world"作为响应内容。

  • 最后,通过app.run()方法启动应用程序。此时,Flask会监听默认的主机和端口(127.0.0.1:5000),等待并处理用户发送的请求。

if __name__ == '__main__':
    app.run()
  • 以上就是一个最简单的Flask应用的示例。当访问根路径"/"时,会返回"hello world"。

  • 需要注意的是,Flask框架还提供了很多其他功能,例如处理静态文件、使用模板引擎渲染页面、处理表单提交等。

【三】登陆案例

  • main.py
# -*-coding: Utf-8 -*-
# @File : 01 初识falsk .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/8/23
from flask import Flask, render_template, request, redirect, session

app = Flask(__name__, template_folder='templates')
app.debug = True
app.secret_key = 'sdfsdfsdfsdf'  # 等同于django的 配置文件有个很长的秘钥

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


@app.route('/login', methods=['GET', 'POST'])
def login():
    # 只要在这个函数中,全局的request 就是当次请求的request对象,等同于django的request
    if request.method == 'GET':  # get请求返回模板
        return render_template('login.html')  # 新手四件套之一,返回模板
    else:
        username = request.form.get('username')
        password = request.form.get('password')
        if username == 'dream' and password == '123':
            # 登录成功,把登录信息,写入到session中
            session['username'] = username

            # 重定向到百度,新手四件套之一,返回重定向
            # return redirect('http://www.baidu.com')

            # 重定向到百度,新手四件套之一,返回重定向
            return redirect('/index')
        else:
            return render_template('login.html', error='用户名或密码错误')


@app.route('/index')
def index():
    # 判断它是否登录,如果登录,显示用户信息
    if session.get('username'):
        return render_template('index.html', users=USERS)
    else:
        return redirect('/login')


@app.route('/detail/<int:pk>')
def detail(pk):
    user = USERS.get(pk)
    return render_template('detail.html', user=user)


if __name__ == '__main__':
    app.run()
  • login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="post">
    <p>用户名:<input type="text" name="username"></p>
    <p>密码:<input type="password" name="password"></p>
    <p><input type="submit" value="提交">{{error}}</p>

</form>


</body>
</html>
  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<h1>用户列表</h1>
<table>
    {% for k,v in users.items() %}
    <tr>
        <td>{{k}}</td>
        <td>{{v.name}}</td>
        <td>{{v['name']}}</td>
        <td>{{v.get('name')}}</td>
        <td><a href="/detail/{{k}}">查看详细</a></td>
    </tr>
    {% endfor %}
</table>
</body>
</html>
  • detail.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<h1>详细信息 {{user.name}}</h1>
    <div>
        {{user.text}}
    </div>

</body>
</html>

【四】登录认证装饰器案例

【1】功能实现

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

app = Flask(__name__, template_folder='templates')
app.debug = True
app.secret_key = 'sdfsdfsdfsdf'  # 等同于django的 配置文件有个很长的秘钥

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


def auth(func):
    def inner(*args, **kwargs):
        if session.get('username'):
            res = func(*args, **kwargs)
            return res
        else:
            return redirect('/login')

    return inner


# 在flask中 使用装饰器 必须加 endpoint 并且每个 路由的 endpoint 都不一样
@app.route('/login', methods=['GET', 'POST'], endpoint='login')
def login():
    # 只要在这个函数中,全局的request 就是当次请求的request对象,等同于django的request
    if request.method == 'GET':  # get请求返回模板
        return render_template('login.html')  # 新手四件套之一,返回模板
    else:
        username = request.form.get('username')
        password = request.form.get('password')
        if username == 'dream' and password == '123':
            # 登录成功,把登录信息,写入到session中
            session['username'] = username

            # 重定向到百度,新手四件套之一,返回重定向
            # return redirect('http://www.baidu.com')

            # 重定向到百度,新手四件套之一,返回重定向
            return redirect('/index')
        else:
            return render_template('login.html', error='用户名或密码错误')


@app.route('/index', endpoint='index')
@auth  # 认证装饰器要放在路由下面 ,只有路由匹配成功才去执行装饰器,进行视图函数的调用
def index():
    # 判断它是否登录,如果登录,显示用户信息
    return render_template('index.html', users=USERS)


@app.route('/detail/<int:pk>', endpoint='detail')
@auth
def detail(pk):
    user = USERS.get(pk)
    return render_template('detail.html', user=user)


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

【2】知识点小结

(1)认证装饰器的位置

  • 认证装饰器应该放在路由装饰器的下方。
  • 这是因为路由装饰器定义了URL路径和HTTP请求方法的匹配规则,只有在路由匹配成功时才会执行相应的视图函数。
  • 此时,通过将认证装饰器放在路由装饰器下方,可以确保只有在路由匹配成功后才执行认证操作,从而保证了访问权限的控制。

(2)路由装饰器中的endpoint参数

  • 在Flask中使用装饰器定义路由时,可以为装饰器添加一个名为endpoint的参数来指定该路由的名称。
    • 如果不指定endpoint,Flask会默认使用被装饰的视图函数的名称作为该路由的名称。
    • 例如,如果使用装饰器定义了两个路由函数indexdetail,且没有指定endpoint参数,那么它们的路由名称将分别为indexdetail
    • 这样,在反向解析URL时,可以使用这些路由名称来生成相应的URL链接。
  • 但如果在装饰器中指定了endpoint参数,例如@app.route('/path', endpoint='custom_endpoint'),那么这个路由的名称将变为custom_endpoint
    • 在使用反向解析生成URL时,需要使用custom_endpoint作为参数来指定该路由的名称。
  • 当你加入了另外一个装饰器如@wrapper时(可以是自定义的装饰器),@app.route装饰器中的endpoint参数将被忽略,而直接使用被装饰的函数的名称作为路由的名称。
    • 这意味着,在反向解析URL时,不再使用custom_endpoint,而是使用被装饰函数的名称来生成URL链接。

(3)装饰器的本质原理

def add(func):
    print(func)


# 类装饰器:1 装饰类的装饰器   2 类作为装饰器

# add一定是个函数吗?
# 可以传入对象(类),作为装饰器使用
class Person:
    def __call__(self, func):
        def inner(*args, **kwargs):
            res = func(*args, **kwargs)
            return res

        return inner


p = Person()


# @add  # test=add(test)--->test变成了None
@p  # test=p(test)
# 当p()被调用时,会触发__call__方法,即Person的 __call__(func)被执行,并返回inner函数
# 以后test就是inner函数
def test():
    print("test")


print(test)


def auth(func):
    def inner(*args, **kwargs):
        # 真正执行视图函数之前,判断用户是否登录并授权
        res = func(*args, **kwargs)
        res.name = 'lqz'
        return res

    return inner


@auth  # Foo=auth(Foo)
class Foo():
    pass


f = Foo()
# Foo()  调用 ---> inner()--->类实例化得到对象,返回,以后f就是Foo的对象
# 但是可以里面多了属性或方法
print(f)
print(f.name)


### 有参装饰器--->额外为被装饰的函数传参数
@auth(10)  # Foo=auth(10)(Foo)
class Foo():
    pass

(4)装饰类的装饰器/类作为装饰器

  • 类装饰器是一种在Python中用于装饰类的装饰器技术。下面详细解释两种类装饰器,并给出示例和注释。

  • 装饰类的装饰器:

    • 装饰类的装饰器是指一个类,它接收一个类作为参数,并返回一个新的类。

    • 这个新的类通常会继承自被装饰的类,并对其进行一些拓展或修改。

  • 示例代码如下:

    def decorator(cls):
        class NewClass(cls):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                self.new_attribute = 'Added attribute'
    
            def new_method(self):
                print("New method")
    
        return NewClass
    
    @decorator
    class OriginalClass:
        def __init__(self):
            self.original_attribute = 'Original attribute'
    
        def original_method(self):
            print("Original method")
    
    obj = OriginalClass()
    obj.original_method()   # Output: "Original method"
    obj.new_method()        # Output: "New method"
    print(obj.original_attribute)  # Output: "Original attribute"
    print(obj.new_attribute)       # Output: "Added attribute"
    
    • 在上述示例中,decorator是装饰类的装饰器。
    • 它接收一个类cls作为参数,并创建一个继承自cls的新类NewClass
    • NewClass中,我们添加了一个新的属性new_attribute以及一个新的方法new_method
    • 通过将装饰器@decorator应用于OriginalClass,我们创建了一个经过装饰的新类OriginalClass,该类继承自原始类,并拥有额外的属性和方法。
  • 类作为装饰器:

    • 类作为装饰器是指一个类,它实现了__call__方法,使得该类的对象可以像函数一样被调用,并用于装饰其他函数或类。
    • 这种装饰器通常会在被装饰对象的前后添加额外的行为或对其进行修改。
  • 示例代码如下:

    class Decorator:
        def __init__(self, func):
            self.func = func
    
        def __call__(self, *args, **kwargs):
            print("Before function execution")
            result = self.func(*args, **kwargs)
            print("After function execution")
            return result
    
    @Decorator
    def decorated_function():
        print("Decorated function")
    
    decorated_function()  # Output: "Before function execution", "Decorated function", "After function execution"
    
    • 在上述示例中,Decorator类实现了__call__方法,使得该类的对象可以像普通函数一样被调用。
    • 通过将装饰器@Decorator应用于函数decorated_function,我们将Decorator类的对象作为装饰器来装饰这个函数。
    • 在函数执行之前和之后,装饰器会输出一些额外的内容,从而拓展了函数的功能。

【补充】wsgiref

  • wsgiref是Python中内置的模块,用于实现WSGI(Web Server Gateway Interface)协议的web服务器。
  • WSGI协议定义了Web应用程序和Web服务器之间的接口,使得开发者可以使用统一的方式来开发Web应用程序。
from wsgiref.simple_server import make_server


def mya(environ, start_response):
    print(environ)
    start_response('200 OK', [('Content-Type', 'text/html')])
    if environ.get('PATH_INFO') == '/index':
        with open('index.html', 'rb') as f:
            data = f.read()

    elif environ.get('PATH_INFO') == '/login':
        with open('login.html', 'rb') as f:
            data = f.read()
    else:
        data = b'<h1>Hello, web!</h1>'
    return [data]


if __name__ == '__main__':
    myserver = make_server('', 8011, mya)
    # 监听本地的8011端口,当请求来了,就会执行    mya()
    # 传入两个参数:
    # 一个是environ:http请求转成python的字典
    # 一个是start_response:响应对象
    print('监听8010')
    myserver.serve_forever()
  • 示例代码中,使用wsgiref模块创建了一个简单的服务器,并定义了一个处理请求的应用函数mya
    • mya函数接收两个参数,environstart_response
      • environ是一个字典,保存了HTTP请求的一些信息,例如请求方法、请求头等。
      • start_response是一个回调函数,用于设置HTTP响应的状态和头部。
  • mya函数中,根据不同的URL路径返回不同的响应内容。
    • 例如,当路径为/index时,读取index.html文件的内容并返回;
    • 当路径为/login时,读取login.html文件的内容并返回;
    • 其他路径则返回一个简单的HTML响应"h1>Hello, web!"。
  • 最后,通过调用make_server函数创建一个服务器对象,指定监听的主机和端口,并将mya函数作为处理函数。
  • 然后调用serve_forever方法启动服务器并一直监听请求。
  • wsgiref模块是Python内置的实现WSGI协议的web服务器模块,可以自定义处理请求的应用函数,并通过make_server函数创建服务器并监听请求。

【补充】Werkzeug

  • Werkzeug是一个WSGI工具包(在它基础上,继续封装),他可以作为一个Web框架的底层库。
  • 这里稍微说一下, werkzeug 不是一个web服务器,也不是一个web框架,而是一个工具包,官方的介绍说是一个 WSGI 工具包,它可以作为一个 Web 框架的底层库,因为它封装好了很多 Web 框架的东西,例如 Request,Response 等等
  • Werkzeug是一个WSGI工具包,它提供了一系列的工具和辅助函数,用于构建Web应用程序。
  • 虽然Werkzeug本身并不是一个完整的Web框架,但它可以作为其他Web框架的底层库,提供与HTTP请求和响应相关的功能。
from werkzeug.wrappers import Request, Response

@Request.application
def hello(request):
    return Response('Hello World!')

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 4000, hello)
  • 示例代码中,使用Werkzeug创建了一个简单的应用函数hello
    • 通过@Request.application装饰器,将hello函数转换为符合WSGI接口的应用对象。
    • hello函数接收一个request参数,代表HTTP请求对象,我们可以从该对象中获取请求的相关信息。
    • 在这个例子中,只是简单地返回一个包含"Hello World!"的响应。
  • 最后,通过run_simple函数来启动一个服务器,指定监听的主机和端口,并将hello应用对象传递给它。
  • Werkzeug是一个WSGI工具包,提供用于构建Web应用程序的工具和功能,可以作为其他Web框架的底层库使用。

posted @ 2023-08-26 21:37  Chimengmeng  阅读(81)  评论(0编辑  收藏  举报