首页 > 编程语言 >学习python-flask

学习python-flask

时间:2022-12-09 23:04:01浏览次数:51  
标签:__ endpoint name python app 学习 flask Flask view

Flask介绍

  • 目前python界,比较出名的web框架
  • django:大而全,web开发用的东西,它都有
  • Flask:小而精,只能完成请求与响应,session,cache,orm, admin则都没有。
    • 可以用很多第三方框架,使flask完全变成django
  • 同步框架:django从3.x改成了异步框架,3.x之前就是同步框架。
  • 异步框架:
    • Tornado:非常少,python2.x上,公司里面用的多一些。
    • Sanic:python3.6及以上
    • FastAPI

Flak

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

“微”(micro) 并不表示你需要把整个 Web 应用塞进单个 Python 文件(虽然确实可以 ),也不意味着 Flask 在功能上有所欠缺。微框架中的“微”意味着 Flask 旨在保持核心简单而易于扩展。Flask 不会替你做出太多决策——比如使用何种数据库。而那些 Flask 所选择的——比如使用何种模板引擎——则很容易替换。除此之外的一切都由可由你掌握。如此,Flask 可以与您珠联璧合。

默认情况下,Flask 不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能,如同是 Flask 本身实现的一样。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask 也许是“微小”的,但它已准备好在需求繁杂的生产环境中投入使用

Flask快速使用

pip3 install flask    # 最新2.2.2

from flask import Flask
app = Flask(__name__)

# 注册路由
@app.route('/index')
def index():
    return '哦吼吼吼或'

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8080)

补充:

脚本:模块导入不会执行,直接当前脚本则会执行脚本内的内容。
魔法方法中的__call__:
    对象()	===>	会触发__call__
    
    类()		===>	会触发元类的__call__
基于socket写服务端----->(封装、socket)---->编写路由和视图函数的wsgiref写服务端。

web框架原理

演变1:基于socket写服务端

import socket

def server_run():
    soc = socket.socket()
    soc.bind(('127.0.0.1', 8008))
    soc.listen(5)
    while True:
        conn, addr = soc.accept()
        recv_data = conn.recv(1024)
        print(recv_data)
        
        
        
        # 1 方式一:可以直接用send发送给客户端
        conn.send(b'HTTP/1.1 200 OK\r\n\r\n<h1>hello web</h1><img src="https://gss2.bdstatic.com/9fo3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike92%2C5%2C5%2C92%2C30/sign=5e3814acf9edab64607f4592965fc4a6/14ce36d3d539b600c0c465d0eb50352ac65cb74b.jpg"></img>')
        
        
        
        # 2 方式二:打开一个html文件
        with open('index.html', 'r', encoding='utf-8') as f:
            data = f.read()
         conn.send(('HTTP/1.1 200 OK\r\n\r\n%s' % data).encode('utf-8'))
        
        
        
        # 3 方式三:动态网页做字符串替换
        import time
        now = time.strftime("%Y-%M-%d %H:%M:%S", time.localtime())
        with open('index.html', 'r', encoding='utf-8')as f:
            data = f.read()

        data = data.replace('@@@', now)
         conn.send(('HTTP/1.1 200 OK\r\n\r\n%s' % data).encode('utf-8'))
        conn.close()

        
        
if __name__ == '__main__':
    server_run()

演变2:基于wsgiref写服务端

from wsgiref.simple_server import make_server


def mya(environ, start_response):
    print('----', environ)  # environ 是http请求进入python后变成了字典
    print('====', start_response)
    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!xzwyb</h1>'
    return [data]


if __name__ == '__main__':
    myserver = make_server('', 8011, mya)
    print('wsgiref-监听8011')
    myserver.serve_forever()

注意
"""
    1. mya是可被调用的对象,加括号能执行。能被调用的是:函数、类、对象加括号。
        p = Person()   p() 会触发Person的__call__
    2. 请求来了会执行mya加括号并把 environ、 start_response 传进去。
        django和flask底层代码原理也是一样的。
    3. environ接收请求数据,start_response 接收请求头。 
"""

演变3:基于wekzeug写服务端

from werkzeug.wrappers import Request, Response


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


if __name__ == '__main__':
    from werkzeug.serving import run_simple

    # 请求来了会执行hello()
    run_simple('localhost', 4000, hello)

总结

'''
总结:
    1 注册路由:@app.route('/detail/<int:id>',methods=['GET'])    methods:允许的请求方式
    2 新手四件套: 
        -返回模板:return render_template('detail.html', **{'user': user}) # context跟djagno不一样
        -返回重定向:return redirect('/login')
        -返回字符串:return '字符串'
        -返回json格式:return jsonify
    3 使用cookie---》就是session,全局的,导入使用即可,必须要指定秘钥
        -放值:session['key']=value
        -取值:session.get('key')
    4 转换器 :@app.route('/detail/<int:id>'),配合视图函数写法
        -def detail(id):
        
    5 前端post请求,提交的数据
        request.form
    6 模板语法:兼容django的dtl,它可以使用 (),字典取值。。。python的语法支持
    
'''

配置文件写法

from flask import Flask

app = Flask(__name__)

# 项目的配置文件:如果不配,有默认的
# 几个重要的
# DEBUG:是否是调试模式
# SECRET_KEY:项目的秘钥
# print(app.config)



# 1 使用配置文件之一:(写小脚本测试阶段用)直接通过app对象,配置上,只能配置几个,本质都要放到app.config中
app.debug=True
app.secret_key='asdfasf4555'
app.session_cookie_name='sss'
print(app.config)


# 2 直接通过app.config 配置
app.config['DEBUG'] = True
app.config['SECRET_KEY'] = 'asfasdf'
print(app.config)

# 3 通过配置文件(很像djagno),不常用
app.config.from_pyfile('settings.py')
print(app.config)

# 4 通过类配置(用的多,可以有多套配置)
app.config.from_object('setting.DevelopmentConfig')
app.config.from_object('setting.ProductionConfig')
print(app.config)

# 5 以下,做了解
app.config.from_envvar("环境变量名称")
app.config.from_json("json文件名称")

# 使用分布式配置中心
import requests
res=requests.get('asdfasdfasdf').json()
app.config.from_mapping(res)
# 拓展:配置文件都在本地

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


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

路由系统

  • flask的路由系统和django的路由还是不一样的,django路由由单独的urls.py,flask中是装饰的形式

  • 使用方式

    @app.route:重要的参数
    	* rule:字符串的路径,使用转换器	<string:name>	<name>
        'default':	UnicodeConverter,
        'string':	UnicodeConverter,
        'any':		AnyConverter,
        'path': 	PathConverter,	 # /xx/sss/
        'int':		IntegerConverter,# 数字
        'float':	FloatConverter,   #小数
        'uuid':     UUIDConverter,    #asdfas-asdfas-asdf
    记住:string,int,path
    * methods:列表,规定请求的方式。如果列表中没有则该请求方式不被支持。
    * endpoint:路由别名,如果不写,会以装饰器的函数作为别名,django中叫name
    
  • flask中路由是使用装饰器的,但是它的本质其实是app对象(Flask)的方法self.add_url_rule(rule, endpoint, f, **options)

  • 如果在视图函数上加装饰器,其实本质是在调用self.add_url_rule

    • 我们可以不加装饰器,自己调用这个方法也能完成路由的注册
from flask import Flask

app = Flask(__name__)

@app.route('/', endpoint='index')  # 本质:index=app.route('/')(index)---->decorator(index)
def index():
    return 'xxx'


def home():
    return 'home'

@app.route('/test',defaults={'name':'lqz'},strict_slashes=True,redirect_to='/home')
def test(name):
    print(name)
    return 'test'

app.add_url_rule('/home', view_func=home, endpoint='home')

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

注意

'''
1 @app.route('/') 先执行完成,结果是decorator内层函数
    @decorator
    def index():
2 index=decorator(index)
    def decorator(f):
        # @app.route('/',endpoint='index') 如果没有传endpoint,这个地方就是None
        endpoint = options.pop("endpoint", None)
        # self是Flask的对象,app :rule路由, endpoint:别名,是None,其他的打散了传入了(methods..)
        self.add_url_rule(rule, endpoint, f, **options)
        return f
3 加了装饰器最终,返回的还是index,只不过执行了 self.add_url_rule(rule, endpoint, f, **options)

4 Flask类中得add_url_rule方法
    -rule:就是装饰器传入的路径,路由
    -endpoint:别名
    -view_func:视图函数不加括号
    
5 得到的结论,现在不需要使用装饰器来注册路由了,自己写
    
    app.add_url_rule('/home', view_func=home, endpoint='home')
    
'''

add_url_rule的参数

@app.route 和 app.add_url_rule参数:
rule:路由(校验规则)

view_func:视图函数名称

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

endpoint = None,别名,反向生成url,即: url_for('别名'),等同与django的reverse

methods = None,允许的请求方式 在@action中也有这个方法,如:['GET', 'POST']

strict_slashes = None 路由后面是否严格要求跟 /

redirect_to = None 重定向

cbv写法

from flask import Flask
from flask.views import MethodView, View

app = Flask(__name__)


继承一个视图基类MethodView,在里面写方法,get请求就会触发get方法
class Login(MethodView):
    decorators = []
    methods = ['POST']

    def get(self):
        return '我是get'

    def post(self):
        return '我是psot'


# class Test(View):
#     def dispatch_request(self):
#         pass
#
#     def get(self):
#         return 'get'


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


# as_view 必须传默认值,这个默认值就是别名endpoint
app.add_url_rule('/login', view_func=Login.as_view('login'), endpoint='xxx')
if __name__ == '__main__':
    app.run()

cbv加装饰器,如何做?

1.	研究第0个问题:cbv加装饰器如何去做?
	类属性中加入decorators = [auth, ], 属性是一个列表按照列表顺序,依次给每个方法加装饰器
    def as_view(cls, name, *class_args, **class_kwargs ) :
       ....
       if cls.decorators:
          for decorator in cls.decorators:
            '''
            # 装饰器原理:
             @auth
             def view():
             本质是  view=auth(view)  
            '''
            # 给view加装饰器----》给视图类中得方法加装饰器
             view = decorator(view) 
        return view

as_view的执行流程

2. 研究第1个问题,as_view的执行流程
	 def as_view(cls, name, *class_args, **class_kwargs):
        def view(**kwargs):
            return self.dispatch_request(**kwargs)
        return view
 
    * 请求来了,路由匹配成功,会执行as_view内的view()----》self.dispatch_request---》MethodView的dispatch_request
    * MethodView的dispatch_request
      def dispatch_request(self, **kwargs):
        # 在当前视图类中反射,请求方式的小写字符串(get),我们写了get方法
        meth = getattr(self, request.method.lower(), None)
        # 执行get()
        return meth(**kwargs) 

Login.as_view(name='index') name到底有什么用

3. 研究第2个问题:Login.as_view(name='index')  name到底有什么用,还必须传。
* 先研究 endpoint 有什么用,正常的fbv,如果不写endpoint,会以函数名作为别名,endpoint如何设置的
* 如果endpoint为None,它把函数名作为了endpoint
	if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)# view_func.__name__
        options["endpoint"] = endpoint
        
        
* Login.as_view(name='index'),name到底有啥用
	** app.add_url_rule('/login', view_func=Login.as_view('login'))
    ** 没有传endpoint这个别名,Login.as_view('login')是 则传的是view函数的内存地址。如果函数都没传endpoint和as_view()里面为空,他们都是共用一个view同名,则会报错的。
	** endpoint会以函数名作为endpoint的值,现在所有函数都是view,必须传入name,来修改调view函数的名字。
    ** 如果传了endpoint,别名以endpoint为主,如果不传endpoint,别名以name为主
    ** app.add_url_rule('/login', view_func=Login.as_view(name='login'),endpoint='xxx')
    

继承View写cbv

继承View写视图类(CBV)
1. 继承View的视图类,执行流程都是一样的。
2. 请求来了,路由匹配成功,执行self.dispatch_request
3. self.dispatch_request 没有实现,直接抛异常 NotImplementedError()
4. 必须重写 dispatch_request, 自己写匹配规则,执行不同的方法。

注意

视图类中还有个类属性 methods = ['POST']
* 用来控制允许的请求方式

模板语法

  • dtl 中得所有语法,它都支持,并且能够使用 函数() 可以传参数。
from flask import Flask, render_template,Markup
app = Flask(__name__)
@app.route('/')
def index():
    # return render_template('test.html', name='lqz', age=19)
    # return render_template('test.html',
    #                        user={
    #                            1: {'name': 'lqz', 'age': 19, 'hobby': '篮球'},
    #                            2: {'name': 'lqz1', 'age': 20, 'hobby': '橄榄球'},
    #                            3: {'name': 'lqz2', 'age': 21, 'hobby': '乒乓球'},
    #                        })

    a='<a href="http://www.baidu.com">点我看美女</a>'
    # a=Markup(a)
    return render_template('test.html',a=a)
if __name__ == '__main__':
    app.run()

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


{#<table>#}
{#    {% for k,v in user.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>#}


{#<table>#}
{#    {% if name %}#}
{#        <h1>Hello {{ name }}!</h1>#}
{#    {% else %}#}
{#        <h1>Hello World!</h1>#}
{#    {% endif %}#}
{#</table>#}


{#{{ a|safe }}#}
{{ a}}


</body>
</html>

标签:__,endpoint,name,python,app,学习,flask,Flask,view
From: https://www.cnblogs.com/bjyxxc/p/16970457.html

相关文章

  • python 操作 MySQL
    python操作MySQL目录python操作MySQL1pymsql1.1下载安装1.2使用操作1.2.1执行SQL1.2.2插入表内容1.2.3fetch数据类型2SQLAchemy2.1安装2.2基本使用2.2.1Fil......
  • python实现简单的商品数据管理系统
    #一个商品名称价格库存总销量#存放商品的数据类型strsetlisttupledict#综合考虑,选择字典dict_data={}#{名称:{price:价格,inventory:库存,sa......
  • 8、V4L2接口学习、显示摄像头画面、集成项目使用
    基本思想:因为手中有一块RK3399PRO的开发板,外接了AHD的摄像头,为了实现实时获取视频帧,所以需要学习一下v4l2编程。。第一步:先拷贝一张图,整个v4l2的取帧流程 具体讲解参考这......
  • [附源码]Python计算机毕业设计Django时间管理软件app
    OverridetheentrypointofanimageIntroducedinGitLabandGitLabRunner9.4.Readmoreaboutthe extendedconfigurationoptions.Beforeexplainingtheav......
  • 算法学习笔记(3)——二分
    二分二分法用于解决这样一类问题:一个区间能分成左右两部分,左半部分满足性质\(A\),右半部分不满足性质\(A\)。问题的目标是求解这两部分的分界点。所以二分法和区间里有......
  • 算法学习笔记(4)——高精度
    高精度高精度高精度加法高精度减法高精度乘法高精度除法高精度加法题目链接:AcWing791.高精度加法题目描述给定两个正整数(不含前导0),计算它们的和。输入......
  • 算法学习笔记(5)——前缀和与差分
    前缀和与差分前缀和与差分一维前缀和差分一维前缀和前缀和可以用于快速计算一个序列的区间和,也有很多问题里不是直接用前缀和,但是借用了前缀和的思想。用\(s[i......
  • python :控制线程上限,防止无限开启线程
    importthreadingsem=threading.Semaphore(10)#设置最大线程数#在线程调用的函数开始设置sem.acquire()#在线程调用的函数最后设置sem.release()defxiazai(iiv,cha......
  • [附源码]Python计算机毕业设计Django网文论坛管理系统
    OverridetheentrypointofanimageIntroducedinGitLabandGitLabRunner9.4.Readmoreaboutthe extendedconfigurationoptions.Beforeexplainingtheav......
  • 算法学习笔记(2)——归并排序
    归并排序归并排序的思想是基于分治法,其思路是:将待排序区间平分成左右两半,左右两侧分别递归地做归并排序。将这两个有序的区间合并(每次落一个较小的下来),就将这个区间排......