Python入门自学进阶-Web框架——42、Web框架了解-bottle、flask

2023-09-22 14:39:44

WEB框架的三大组件:路由系统、控制器(含模板渲染)、数据库操作

微型框架:依赖第三方写的socket,WSGI,  本身功能少

安装:
pip install bottle


pip install flask

安装flask,同时安装了MarkupSafe、Werkzeug、Jinja2、itsdangerous。
Werkzeug是Python的WSGI规范的实用函数库。使用广泛,基于BSD协议,是Flask使用的底层WSGI库;
itsdangerous是flask中引用的一个第三方包,用来解决生成token等网络安全问题;
MarkupSafe为 Python 实现 XML/HTML/XHTML 标记安全字符串;
Jinja2是一个模板语言,是一个现代的、设计友好的、依照django模板的python模板语言;

pip install tornado

已经安装过。

Bottle:

一个程序文件完成整个网站:

from bottle import template,Bottle
root = Bottle()

@root.route('/hello/')  
# 装饰器,定义了URL,即/hello/这个url由index这个函数来处理,就是路由系统
def index():
    return "Hello World!"

root.run(host='localhost', port=8080)
# 这里就是启动webserver服务器,然后等待请求

运行整个Python程序:

浏览器端请求:

上面的路由(即装饰器)是静态路由,还可以使用动态路由:

@root.route('/wiki/<pagename>')
def
 callback(pagename):
    ...

pagename作为参数变量名,匹配字符串。

@root.route('/object/<id:int>')
def
 callback(id):
    ...
id是一个int型的参数变量名。

@root.route('/show/<name:re:[a-z]+>')
def
 callback(name):
   ...
name是一个正则表达式参数变量。

@root.route('/static/<path:path>')
def
 callback(path):
    
return static_file(path, root='static')
定义路径,类似Django中的静态文件路径,主要是定义文件在服务器存储中的位置。

root指定的是项目中的一个目录,这里指定了项目中的static,在这个目录下有testcss.css文件,可以访问:

修改一下:

如果root为'static'不变,还可以这样访问:

对于路由对应的函数,除了返回字符串,还可以使用模板:

@root.route('/hello/')
# 装饰器,定义了URL,即/hello/这个url由index这个函数来处理
def index():
    # return "Hello World!"
    return template('<b>Hello {{name}}!</b>',name="小花")

对于template(),除了像上面直接在其中写模板外,还可以直接指定一个模板文件,如

return template(‘index.html’)

创建index.html文件。这里要注意的是默认bottle找模板的路径,在bottle中有如下配置变量

TEMPLATE_PATH = ['./', './views/'],即默认模板查找顺序是先在项目根目录,然后是views目录,我们可以添加自己定义的目录

最终程序:

from bottle import template,Bottle,static_file
import bottle
bottle.TEMPLATE_PATH.append('./templates/')

root = Bottle()


# 装饰器,定义了URL,即/hello/这个url由index这个函数来处理
@root.route('/hello/')
def index():
    print(bottle.TEMPLATE_PATH)
    # return "Hello World!"
    # return template('<b>Hello {{name}}!</b>',name="小花")
    return template("index.html")

@root.route('/sta/<path:path>')
def callback(path):
    return static_file(path,root='static')

root.run(host='localhost', port=8080)

运行程序后,打印的TEMPLATE_PATH为:['./', './views/', './templates/'],但是却找不到模板文件:

经过反复的测试,查找资料,这个问题我个人的理解是:

这个路径是linux系统的路径,在windows系统下失去效果,windows系统下,需要添加windows的绝对路径,使用os.path.abspath(os.path.join(os.path.dirname(__file__), "views")来获取windows下的绝对路径:

from bottle import run,template,Bottle,TEMPLATE_PATH
import os
app = Bottle()
TEMPLATE_PATH.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "templates")))
TEMPLATE_PATH.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "views")))
print(TEMPLATE_PATH)

@app.route('/')
@app.route('/hello/<name>')
def index(name='default'):
    return template('hello.html',name=name)

run(app,host='localhost',port=8080)

这时的TEMPLATE_PATH为:

['D:\\website\\bottlepro\\templates', './', './views/', 'D:\\website\\bottlepro\\views']

这时再访问,就没有问题了。

请求方法路由

@root.route('/hello/', method='POST')
def index():
    ...
 
@root.get('/hello/')
def index():
    ...
 
@root.post('/hello/')
def index():
    ...
 
@root.put('/hello/')
def index():
    ...
 
@root.delete('/hello/')
def index():
    ...

一个简单的登陆:

from bottle import template,Bottle,static_file,TEMPLATE_PATH,request,redirect
import os

TEMPLATE_PATH.append(os.path.abspath(os.path.join(os.path.dirname(__file__),'templates')))
root = Bottle()

# 装饰器,定义了URL,即/hello/这个url由index这个函数来处理
@root.route('/login/',method=['GET','POST'])
def login():
    if request.method == "GET":
        return template('login.html')
    else:
        # v = request.forms  # POST的数据都保存
        # v = request.query  # GET发来的请求数据
        # v = request.body   # POST发来的请求数据
        u = request.forms.get('user')
        p = request.forms.get('pwd')
        print(u,p)
        return redirect('/index/')
@root.route('/index/')
def index():
    return template('index.html')

@root.route('/sta/<path:path>')
def callback(path):
    return static_file(path,root='static')

root.run(host='localhost', port=8080)
# 这里就是启动webserver服务器,然后等待请求
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>Bottle登录</h1>
    <form action="/login/" method="post">
        <input type="text" name="user" placeholder="用户名">
        <input type="password" name="pwd" placeholder="密码">
        <input type="submit" value="提交">
    </form>
</body>
</html>

Bottle中的request其实是一个LocalReqeust对象,其中封装了用户请求的相关信息:

request.headers     :    请求头信息

request.query         :    get请求信息

request.forms         :     post请求信息

request.files            :    上传文件信息

request.params       :     get和post请求信息

request.GET             :     get请求信息

request.POST           :     post和上传信息

request.cookies        :     cookie信息     

request.environ        :     环境相关相关

bottle的模板,在使用for循环遍历列表生成<ul><li>时的问题:

@root.route('/index/')
def index():
    user_list = [
        {'id': 1, 'name': 'root1', 'age': 18},
        {'id': 2, 'name': 'root2', 'age': 19},
        {'id': 3, 'name': 'root3', 'age': 20},
        {'id': 4, 'name': 'root4', 'age': 21},
    ]
    return template('index.html', user_list=user_list)

模板index.html:

<body>
    {{user_list}}
    <hr/>
    <ul>
    % for item in user_list :
        <li>{{item}}<li/>
    % end
    </ul>
</body>

预想的是这样:

实际是这样:

多出来的这些空行,都是<li>::marker</li>,为何会多产生这些标签??怎么去掉?希望高手指点一二。

Flask:

基本框架与Bottle差不多,如下:

from flask import Flask

app = Flask(__name__)

@app.route('/index/')
def index():
    return "hello world!"

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

启动后:

默认是在5000端口。访问:

在Flask()中,可以对静态文件和模板路径进行配置:相关参数如下

默认模板路径就是templates,

这个不像Bottle,项目下创建了templates,就可以直接找到。

传递参数:

@app.route('/index/')
def index():
    # return "hello world!"
    return render_template('flaskindex.html',k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17})

模板:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>Flask index</h1>
    {{k1}} <!-- 单值 -->
    {{k2}} <!-- 列表 -->
    <hr/>
    <ul>
        {% for item in k2 %}
            <li>{{item}}</li>
        {% endfor %}
    </ul>
    {{k3}} <!-- 字典 -->
    <hr/>
    {% for k,v in k3.items() %}
        {{k}}--{{v}}<br>
    {% endfor %}
</body>
</html>

还可以传递函数:

模板中:要在变量后加上小括号

Flask的动态路由方式:

  • @app.route('/user/<username>')
  • @app.route('/post/<int:post_id>')
  • @app.route('/post/<float:post_id>')
  • @app.route('/post/<path:path>')
  • @app.route('/login', methods=['GET', 'POST'])

DEFAULT_CONVERTERS = {
    'default':          UnicodeConverter,
    'string':           UnicodeConverter,
    'any':              AnyConverter,
    'path':             PathConverter,
    'int':              IntegerConverter,
    'float':            FloatConverter,
    'uuid':             UUIDConverter,
}

与bottle一样,也有方法请求路由,即在路由中增加“method=”参数

对于Http请求,Flask会讲请求信息封装在request中(werkzeug.wrappers.BaseRequest),提供的如下常用方法和字段以供使用:

request.method
request.args
request.form
request.values
request.files
request.cookies
request.headers
request.path
request.full_path
request.script_root
request.url
request.base_url
request.url_root
request.host_url
request.host

Flask中使用cookie:使用make_response函数包装render_template,生成的对象有set_cookie方法。先导入make_response

@app.route('/index/')
def index():
    # return "hello world!"
    # return render_template('flaskindex.html',k0=myfun,k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17})
    obj = make_response(render_template('flaskindex.html',k0=myfun,k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17}))
    obj.set_cookie('usern','xiaohua')
    return obj

Flask中重定向:redirect

url_for(别名),这里的别名就是函数名,不需要在route中单独定义

Flask中使用session,先导入session,from flask import session

要使用session,需要先配置一个SECRET_KEY,在Flask对象上设置,设置后才能在函数中使用:session['key']=value的方式

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

app = Flask(__name__)
app.config.update(SECRET_KEY=b'_5#y2L"F4Q8z\n\xec]/') # 要使用session,必须设置这个参数

def myfun():
    return "<a>测试传递函数</a>"

@app.route('/index/')
def index():
    # return "hello world!"
    # return render_template('flaskindex.html',k0=myfun,k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17})
    obj = make_response(render_template('flaskindex.html',k0=myfun,k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17}))
    obj.set_cookie('usern','xiaohua')
    return obj

@app.route('/login/',methods=['GET','POST'])
def login():
    if request.method =='POST':
        session['user'] = request.form.get('user') # 设置session内容
        url = url_for('redirectaliastest')

        return redirect(url)
    else:
        return render_template('login.html')

@app.route('/testurlfor')
def redirectaliastest():
    print(session)  # login中设置的session在这里能打印出
    return render_template('flaskindex.html')

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

关于Flask的中间件调用机制:

所有的WSGI在执行时,即实例化时,要先执行__call__()方法,

def __call__(self, environ: dict, start_response: t.Callable) -> t.Any:

    return self.wsgi_app(environ, start_response)

这个方法返回的是是执行wsgi_app方法的结果,然后在进入到Flask。

我们可以将这个wsgi_app换成我们自定义的类,在__call__方法中添加我们自己的代码,最后在调用原来的wsgi_app,这样就在请求处理前,先经过了我们自己的处理,像Django的中间件就是这种机制实现的。

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

app = Flask(__name__)
app.config.update(SECRET_KEY=b'_5#y2L"F4Q8z\n\xec]/')

def myfun():
    return "<a>测试传递函数</a>"

@app.route('/index/')
def index():
    # return "hello world!"
    # return render_template('flaskindex.html',k0=myfun,k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17})
    obj = make_response(render_template('flaskindex.html',k0=myfun,k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17}))
    obj.set_cookie('usern','xiaohua')
    return obj

@app.route('/login/',methods=['GET','POST'])
def login():
    if request.method =='POST':
        session['user'] = request.form.get('user')
        url = url_for('redirectaliastest')

        return redirect(url)
    else:
        return render_template('login.html')

@app.route('/testurlfor')
def redirectaliastest():
    print(session)
    return render_template('flaskindex.html')

class Foo:
    def __init__(self,w):
        self.w = w

    def __call__(self, environ,start_response):
        print("自己的中间件")
        obj = self.w(environ,start_response)
        return obj
if __name__ == "__main__":
    app.wsgi_app = Foo(app.wsgi_app)  
    # 将原来的wsgi_app换成我们的类,Foo加上括号,即Foo()会先init,然后call
    # call的时候先执行我们的逻辑(相当于中间件),最后执行原来的wsgi_app
    # 这种方法有点装饰器的设计模式
    app.run()

启动后,页面请求过程:

Flask的消息:取一次就消失:

放置在session中,使用flash(value),取用,get_flashed_message(),取完就删除了。

更多推荐

二、vue2脚手架-组件化开发

|vue中的图片打包后会转换为base64格式组件的使用1.创建组件:component文件夹中创建HelloWorld.vue文件2.在app.vue中引入组件组件间的通信/传值(常用)一、prop父传子1.App.vue中的引入组件中创建需要传递的数据2.在子组件中接收并确定父组件传递过来的数据类型more规定接收

【区域生长】代码

以下是基于Python的区域生长法完整代码:importnumpyasnpimportcv2#读入原始光学影像并转为灰度图像img=cv2.imread('optical_image.jpg',cv2.IMREAD_GRAYSCALE)#设定种子点(滑坡区域)seed_point=(200,200)#设定生长阈值thr

redis深度历险 2 - Redis的基本数据类型以及使用场景

Redis的基本数据类型包括五种:String(字符串)、Hash(哈希)、List(列表)、Set(集合)及ZSet(有序集合)。String(字符串)类型:简介:String是最基本的数据类型,也是最重要的类型之一,一个key对应一个value,可以是字符串、整型、浮点等,String的最大储存值为512MB。缓存

log4j2或者logback配置模版实现灵活输出服务名

介绍在我们使用log4j2或者logback打印日志时,输出的内容中通常是一定要加上服务名的。以log4j2为例:<!--输出控制台的配置--><Consolename="Console"target="SYSTEM_OUT"><!--输出日志的格式--><PatternLayoutpattern="server-ca

Redis GEO 类型与 API 结合,地理位置优化的绝佳实践

🔭嗨,您好👋我是vnjohn,在互联网企业担任Java开发,CSDN优质创作者📖推荐专栏:Spring、MySQL、Nacos、Java,后续其他专栏会持续优化更新迭代🌲文章所在专栏:MySQL、Redis、业务设计🤔我当前正在学习微服务领域、云原生领域、消息中间件等架构、原理知识💬向我询问任何您想要的东西

JavaWeb 学习笔记 3:Servlet

JavaWeb学习笔记3:Servlet1.简介Servlet是JavaEE定义的一套Web应用开发标准(接口),实现了该技术的Web服务器软件(如Tomcat)上可以运行一个Servlet容器,只要我们使用Servlet技术开发Web应用,就可以打成war包后放在Web服务器上,Web服务器软件可以自动解包,并执行其

vSAN数据恢复-vSAN架构下虚拟机磁盘组件出现问题的数据恢复案例

vsan数据恢复环境:一套VMwarevSAN超融合基础架构,全闪存,开启压缩重删。共11台服务器节点。每台服务器节点上配置1块PCIE固态硬盘和8-10块SSD固态硬盘。每个服务器节点上创建1个磁盘组,每个磁盘组将1个PCIE固态硬盘识别为2个硬盘作为缓存盘,将8-10个SSD固态硬盘作为容量盘,共同组成vSAN存储

AMEYA360 | 罗姆ROHM面向工业设备应用的产品目录上线

作为半导体和电子元器件制造商,罗姆集团自成立后60多年以来,一直秉持“质量第一”的企业目的,为消费电子设备和IT设备、汽车以及工业设备等多个领域源源不断地提供高品质、可信赖的产品。随着“节能”和“小型化”需求的不断高涨,罗姆集团以功率半导体和模拟半导体为中心,正面向“工厂自动化”、“能源”和“基础设施”等工业设备市场,

建议收藏《Verilog代码规范笔记_华为》(附下载)

华为verilog编程规范是坊间流传出来华为内部的资料,其贴合实际工作需要,是非常宝贵的资料,希望大家善存。至于其介绍,在此不再赘述,大家可看下图详细了解,感兴趣的可私信领取《Verilog代码规范笔记_华为》。…………一共10页想获得完整版《Verilog代码规范笔记_华为》的小伙伴赶快私信获取!另外,今天精选了几道

ITIL是什么?

ITIL是什么?1.ITIL是什么?2.ITIL4个版本2.1ITILV1-关注IT基础架构的管理2.2ITILV2-以流程为核心(5个服务支持流程和5个服务交付流程)2.3ITILV3-服务生命周期2.4ITIL4-最新版本,强调价值创造2.5ITILV1,V2,V3到ITIL4时间线3.ITIL4有哪些内容?3.1

ISTQB术语表

此术语表为国际软件测试认证委员会(ISTQB)发布的标准术语表。此表历经数次修改、完善,集纳了计算机行业界、商业界及政府相关机构的见解及意见,在国际化的层面上达到了罕有的统一性及一致性。参与编制此表的国际团体包括澳大利亚、比利时、芬兰、德国、印度、以色列、荷兰、挪威、葡萄牙、瑞典、英国和美国。多数软件测试工程师使用19

热文推荐