Flask学习笔记

参考 W3Cschool: Flask 教程

Flask 概述

  • Flask基于Werkzeug WSGI工具包和Jinja2模板引擎。
    • WSGI:Web Server Gateway Interface(Web服务器网关接口,WSGI)已被用作Python Web应用程序开发的标准。 WSGI是Web服务器和Web应用程序之间通用接口的规范。
    • Werkzeug是一个WSGI工具包,它实现了请求,响应对象和实用函数。 这使得能够在其上构建web框架。 Flask框架使用Werkzeug作为其基础之一。
    • jinja2是Python的一个流行的模板引擎。Web模板系统将模板与特定数据源组合以呈现动态网页。

安装: conda install Flask

flask 应用

import flask
app = flask.Flask(__name__)

# # http://127.0.0.1:5000/h
@app.route('/')
def hello_world():
   return 'Hello World'

def hi():
    return 'hi'

# view_func 一定要是函数名
# http://127.0.0.1:5000/hi
app.add_url_rule(rule='/hi/',view_func=hi)

# 动态URL
@app.route('/hello/<user_name>/')
def hello(user_name):
    return 'hello:' + str(user_name)

# 整数
@app.route('/int/<int:user_id>/')
def theId(user_id):
    return 'id:' + str(user_id)

# 浮点数
@app.route('/float/<float:pi>/')
def thePI(pi):
    return 'float:' + str(pi)


# path
@app.route('/path/<path:p>/')
def thePath(p):
    return 'float:' + str(p)

# for guest
@app.route('/guest/<user_name>')
def hi_guest(user_name):
    return 'hi GUEST:' + user_name

# for admin
@app.route('/admin/<user_name>')
def hi_admin(user_name):
    if user_name=='admin':
        return 'hi ADMIN'
    else:
        return flask.redirect(flask.url_for('hi_guest',user_name=user_name))

if __name__ == '__main__':
    app.run(host='127.0.0.1',port='5000',debug=True)
  • Flask类的实例,这里的app是我们的WSGI应用程序
  • Flask构造函数使用当前模块的名称 (__name __) 作为参数。
  • Flask类的route()函数是一个装饰器,它告诉应用程序哪个URL应该调用相关的函数: app.route(rule, options)
    • rule 参数表示与该函数绑定的 URL,在上面的示例中,/ URL与hello_world()函数绑定。因此,当在浏览器中打开web服务器的主页时,将呈现该函数的输出。
    • options 是要转发给基础Rule对象的参数列表
  • Flask类的run()方法在本地开发服务器上运行应用程序: app.run(host, port, debug, options)
    • host:要监听的主机名。 默认为127.0.0.1(localhost)。设置为“0.0.0.0”以使服务器在外部可用
    • port:默认值为5000
    • debug:默认为False。 如果设置为True,则提供调试信息
    • options:要转发到底层的Werkzeug服务器。
  • 添加路由的两种方式
    • route()装饰器
    • application对象的add_url_rule()函数
  • 路由定义要求:Flask的URL规则基于Werkzeug的路由模块。这确保形成的URL是唯一的,并且基于Apache规定的先例。一句话:URL路由最后加/,否则会导致404
  • 动态URL:通过向规则参数添加变量部分,可以动态构建URL。此变量部分标记为<variable-name>。它作为关键字参数传递给与规则相关联的函数。
    • 默认参数为字符串
    • 其他类型
      • int:接受整数
      • float:接受浮点值
      • path:接受用作目录分隔符的斜杠
  • 使用url_for函数重定向 url: url_for 函数接受函数的名称作为第一个参数(跳转到该参数对应的函数的URL),以及一个或多个关键字参数,每个参数对应于跳转的函数的 URL变量.

Flask 模板

简单来讲,模板就是渲染页面时,渲染函数的一个参数。

把业务逻辑和表现内容放在一起,会增加代码的复杂度和维护成本.

  • 模板其实是一个包含响应文本的文件,其中用占位符(变量)表示动态部分,告诉模板引擎其具体的值需要从使用的数据中获取
  • 使用真实值替换变量,再返回最终得到的字符串,这个过程称为'渲染'
  • Flask 是使用 Jinja2 这个模板引擎来渲染模板

使用模板的好处

  • 视图函数只负责业务逻辑和数据处理(业务逻辑方面)
  • 而模板则取到视图函数的数据结果进行展示(视图展示方面)
  • 代码结构清晰,耦合度低

模板基本使用:在项目下创建 templates 文件夹,用于存放所有模板文件。 在目录下创建一个模板文件 html 文件 hello.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
我的模板html内容

<!--模版中使用传入的变量 -->
<br />{{ my_str }}
<br />{{ my_int }}
<br />{{ my_array }}
<br />{{ my_dict }}

</body>
</html>

可以在应用中渲染模板文件返回:

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    # 可以向模板传入的数据
    my_str = 'Hello Word'
    my_int = 10
    my_array = [3, 4, 2, 1, 7, 9]
    my_dict = {
        'name': 'xiaoming',
        'age': 18
    }

    return render_template('hello.html',my_str=my_str,
                           my_int=my_int,
                           my_array=my_array,
                           my_dict=my_dict)

if __name__ == '__main__':
    app.run(host='127.0.0.1',port='5000',debug=True

模板变量: 代码中传入到模板中的字符串,列表,字典

post方法

默认情况下,Flask路由响应GET请求。但是,可以通过为route()装饰器提供方法参数来更改此首选项。

为了演示在URL路由中使用POST方法,首先让我们创建一个HTML表单,并使用POST方法将表单数据发送到URL.

创建表单文件 login.html ,并放在 templates 目录下:

<html>
   <body>
      <form action = "http://127.0.0.1:5000/login/" method = "post">
         <p>Enter Name:</p>
         <p><input type = "text" name = "nm" /></p>
         <p><input type = "submit" value = "submit" /></p>
      </form>

   </body>
</html>

应用:

import flask
app = flask.Flask(__name__)

@app.route('/success/<user_name>')
def success(user_name):
   return 'welcome '  + user_name

@app.route('/login/',methods = ['POST', 'GET'])
def login():
   if flask.request.method == 'POST':
      user = flask.request.form['nm']
      return flask.redirect(flask.url_for('success',user_name=user))
   else:
      return flask.render_template('login.html')

if __name__ == '__main__':
    app.run(host='127.0.0.1',port='5000',debug=True)

Flask 静态文件

在开发过程中,静态文件是从包或模块旁边的static文件夹中提供,它将在应用程序的路由 /static 中被调用。

hello.js 文件内容:

function sayHello() {
   alert("Hello World")
}

在如下的 index.html 中,点击按钮 Say Hello 会调用该js中的函数 sayHello()

<html>

   <head>
      <script type = "text/javascript" 
         src = "{{ url_for('static', filename = 'hello.js') }}" ></script>
   </head>

   <body>
      <input type = "button" onclick = "sayHello()" value = "Say Hello" />
   </body>

</html>

应用:

from flask import Flask, render_template

app = Flask(__name__)

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

    return render_template('index.html')

if __name__ == '__main__':
    app.run(host='127.0.0.1',port='5000',debug=True)

使用UI库: element-ui

参考:

https://unpkg.com/browse/element-ui@2.14.0/ 下载最新版本代码到本地文件夹 static。

参考 unpkg.com下载(pyhton)脚本分享下载文件:

  • 下载脚本unpkg.com.py 放在 static 目录下
  • 下载前指定组件版本, element UI 支持的是 vue版本2.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
unpkg.com.py
参考: https://www.jianshu.com/p/6b58bdc9fc6f
"""

import requests,re,os,time,shutil

url="https://unpkg.com/"
headers={ 'Accept-Language': 'zh-CN,zh;q=0.8',
            'Content-Type': 'text/html;Charset=utf-8',
            "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36"
            }
#获取HTML
def getHTML(url,encoding='utf-8'): 
    rd = requests.get(url, params=None, headers=headers)
    rd.encoding = encoding
    return rd.text

#获取版本
def getVsions(m): 
    h=getHTML(url+m+'/') 
    j=re.findall(r'<select name="version"(.*?)</select>', h,re.S)[0] 
    patt = re.compile(r'<option.+?>(.+?)</option>')
    option = patt.findall(j)
    return option

#扫描目录
def getPaths(v,p='/',files=[],folders=[]): 
    h=getHTML(url+v+p) 
    t=re.findall(r'<table(.*?)</table>', h,re.S)[0] 
    href = re.findall('href="(.*?)"',t)
    for name in href: 
        path=p+name
        #if name in ['../','LICENSE'] or not 'iconfont' in path:#material-design-icons
        if name in ['../','LICENSE'] or path in ['/src/','/packages/','/types/','/dist/docs/','/docs/','/samples/',"/test/","/locale/"] :#跳过
            continue
        print(path)
        if name[-1]=='/':
            folders.append(path)
            getPaths(v,path,files,folders)
        else:
            files.append(path)
    return {"files":files,"folders":folders}

#创建目录
def makeDirs(dirs,p):
    if p==None:
        p='./' 
    for  i in dirs:
        path=p+i
        if not os.path.exists(path):
            print("创建目录",path)
            os.makedirs(path)

#下载文件
def download(url,path=None):#dir=保存文件夹路径
    if not os.path.exists(path):
        print("下载:",url)
        r=requests.get(url)
        t=str(time.time())+'.'+str(pid)+'.tmp'
        open(t, 'wb').write(r.content) 
        shutil.move(t, path) 
    else:
        print("文件已存在")

if __name__=='__main__':
    mod="element-ui"
    pid=os.getpid() 
    print(url+mod+'/')
    versions=getVsions(mod)
    print("所有版本:",versions)
    version=mod+'@'+versions[-1]
    print("默认版本:",version)
    version="element-ui@2.14.0" 
    paths=getPaths(version) 
    makeDirs(paths["folders"],version)
    for i in paths["files"]:
        u=url+version+i
        download(u,version+'/'+i)
    print("完成")


    mod="vue"
    pid=os.getpid() 
    print(url+mod+'/')
    versions=getVsions(mod)
    print("所有版本:",versions)
    version=mod+'@'+versions[-1]
    print("默认版本:",version)
    version="vue@2.6.12" 
    paths=getPaths(version) 
    makeDirs(paths["folders"],version)
    for i in paths["files"]:
        u=url+version+i
        download(u,version+'/'+i)
    print("完成")

引入:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <script src="/static/js/echarts.js"></script>
  <!-- import CSS -->
  <link rel="stylesheet" href="/static/element-ui@2.14.0/lib/theme-chalk/index.css">
</head>
<body>
  <div id="app">
    <el-button @click="visible = true">Button</el-button>
    <el-dialog :visible.sync="visible" title="Hello world">
      <p>Try Element</p>
    </el-dialog>
  </div>
</body>
   <!-- import Vue before Element -->
 <script src="/static/vue@2.6.12/dist/vue.js"></script>
 <!-- import JavaScript -->
 <script src="/static/element-ui@2.14.0/lib/index.js"></script>
  <script>
    new Vue({
      el: '#app',
      data: function() {
        return { visible: false }
      }
    })
  </script>
</html>

模版继承

父模版: base.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <script src="/static/js/echarts.js"></script>
    <!-- import CSS -->
    <link rel="stylesheet" href="/static/element-ui@2.14.0/lib/theme-chalk/index.css">
</head>

<body>
    <div id="app">

        {% block content %}
        {% endblock %}

</body>
<!-- import Vue before Element -->
<script src="/static/vue@2.6.12/dist/vue.js"></script>
<!-- import JavaScript -->
<script src="/static/element-ui@2.14.0/lib/index.js"></script>
<script>
    new Vue().$mount('#app')
</script>

</html>

某个子模版:index.html

{% extends 'base.html' %}

{#  重写block #}
{% block content %}

<el-menu :default-active="activeIndex2" class="el-menu-demo" mode="horizontal" @select="handleSelect"
  background-color="#545c64" text-color="#fff" active-text-color="#ffd04b">
  <el-menu-item index="1">处理中心</el-menu-item>
  <el-submenu index="2">
    <template slot="title">我的工作台</template>
    <el-menu-item index="2-1">选项1</el-menu-item>
    <el-menu-item index="2-2">选项2</el-menu-item>
    <el-menu-item index="2-3">选项3</el-menu-item>
    <el-submenu index="2-4">
      <template slot="title">选项4</template>
      <el-menu-item index="2-4-1">选项1</el-menu-item>
      <el-menu-item index="2-4-2">选项2</el-menu-item>
      <el-menu-item index="2-4-3">选项3</el-menu-item>
    </el-submenu>
  </el-submenu>
  <el-menu-item index="3" disabled>消息中心</el-menu-item>
  <el-menu-item index="4"><a href="https://www.ele.me" target="_blank">订单管理</a></el-menu-item>
</el-menu>

{% endblock %}

windows系统chrome浏览器报错,css类型错误

报错信息:

Resource interpreted as Stylesheet but transferred with MIME type text/html

解决方案,假定已经设置静态文件夹:

from flask import send_from_directory

# Flask: Resource interpreted as Stylesheet but transferred with MIME type text/html
@app.route('/css/<path:path>')
def send_css(path):
    return send_from_directory('css', path,mimetype='text/css')
© Licensed under CC BY-NC-SA 4.0

天地不仁,以万物为刍狗;圣人不仁,以百姓为刍狗。—— 老子

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!