Flask入门到进阶(持续更新......)

kobe

一、 flask简介

Flask是一个使用 Python编写的轻量级 Web 应用框架。其 WSGI工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 。

WSGI

Web服务器网关接口(WSGI)已被用作Python Web应用程序开发的标准。WSGI是Web服务器和Web应用程序之间通用接口的规范。

Werkzeug

它是一个WSGI工具包,它实现了请求,响应对象和其他实用函数。这使得能够在其上构建Web框架。Flask框架使用Werkzeug作为其基础之一。

Jinga2

Jinja2是Python的一个流行的模板引擎。Web模板系统将模板与特定数据源组合以呈现动态网页。Flask通常被称为微框架。它旨在保持应用程序的核心简单而可扩展。Flask没有用于数据库处理的内置抽象层,也没有形成验证支持。相反,Flask支持扩展以向应用程序添加此类功能。


二、flask路由

路由定义

处理url和函数之间绑定关系的程序,是指Flask 根据客户端请求 的 URL,查找对应的视图函数 (view function),由视图函数进行处理后,返回 response 到客户端。

路由作用

路由控制访问的路径,路径能访问到什么是由后端来控制的

1 route装饰器 :可以使用Flask应用实例的route装饰器将一个URL规则绑定到 一个视图函数上。
# -*- coding:utf8 -*-

from flask import Flask

app = Flask(__name__)


@app.route('/index')
def index():
    return '<h1>index page</h1>'

if __name__ == '__main__':
    # url_map :  储存 url 和 endpoint 的映射(url_map 的数据类型是 werkzeug.routing.Map)
    print(app.url_map)
    app.run(port=5000,debug=True)

2 add_url_rule方法定义路由

add_url_rule() :另一种等价的写法是使用Flask应用实例的add_url_route()方法。

route装饰器内部也是通过调用add_url_route()方法实现的路由注册。 但是显然,使用装饰器使代码看起来更优雅一些。

# -*- coding:utf8 -*-

from flask import Flask

app = Flask(__name__)


def about(user_id):
    return 'about page %d' % user_id


app.add_url_rule(rule='/about/<int:user_id>',view_func=about)


if __name__ == '__main__':
    app.run(port=5000, debug=True)
3 自定义路由(需要重新定义父类。注意python2与python3的差别!!!)
# -*- coding:utf8 -*-
from flask import Flask
from werkzeug.routing import BaseConverter        #导入转换器包

app = Flask(__name__)

# flask自带几种转换器
DEFAULT_CONVERTERS = {
    'default':          UnicodeConverter,
    'string':           UnicodeConverter,
    'any':              AnyConverter,
    'path':             PathConverter,
    'int':              IntegerConverter,
    'float':            FloatConverter,
    'uuid':             UUIDConverter,
}


# 自定义路由表达式
class RegexConverter(BaseConverter):
  
    def __init__(self, url_map, regex):
        super(RegexConverter,self).__init__(map=url_map)    # python2 重写父类super需要传入子类参数
        # super().__init__(map=url_map)                     # python3 重写父类super不需要传入子类参数
        # self.regex = r'1[3-9]{2}\d{8}'
        self.regex = regex


# 自定义路由表达式:手机号匹配
class MobileConverter(BaseConverter):
    def __init__(self, url_map):
        super(MobileConverter,self).__init__(map=url_map)   # python2 重写父类super需要传入子类参数
        # super().__init__(map=url_map)                     # python3 重写父类super不需要传入子类参数
        self.regex = r'1[3-9]{2}\d{8}'



# 将自定义转换器类添加到转换器字典中
app.url_map.converters['re'] = RegexConverter
app.url_map.converters['mobile'] = MobileConverter


# @app.route('/goods/<float:hello>')
# @app.route('/goods/<int:hello>')
@app.route('/goods/<string:hello>')    # hello 参数为变量
def index(hello):
    return 'hello world %s' % hello


@app.route('/index/<re(r"1[3-9]{2}\d{8}"):test1>')
def sed(test1):
    return "<h1>this for test %s</h1>" % test1


@app.route('/send/<mobile:mobile>')
def send(mobile):
    print ("phone number is %s " % mobile)
    return "<h1>your phone number is %s </h1>" % mobile


if __name__ == '__main__':
    print(app.url_map)
    app.run(host='0.0.0.0',debug=True,port=2000)

4 多个装饰器实现多个路由,/,/h1,/index都可以映射同一函数
# -*- coding:utf8 -*-

from flask import Flask

app = Flask(__name__)


# 多个装饰器可以实现多个路由功能
@app.route('/index')
@app.route('/')
@app.route('/h1')
def index():

    return '<h1>index page</h1>'


if __name__ == '__main__':
    app.run(port=5000,debug=True)
5 路由请求方式设置,methods参数可以提供可选的请求方式
# -*- coding:utf8 -*-
from flask import Flask

app = Flask(__name__)


@app.route('/post',methods=['POST','GET','PUT','DELETE'])
def only():
    return 'post only page'


if __name__ == '__main__':
    print app.url_map
    app.run(host='0.0.0.0',debug=True,port=2000)
6 flask URL构建

url_for()函数对于动态构建特定函数的URL非常有用。该函数接受函数的名称作为第一个参数,以及一个或多个关键字参数,每个参数对应于URL的变量部分。

以下脚本演示了如何使用url_for()函数:
# -*- coding:utf8 -*-
from flask import Flask, redirect, url_for
app = Flask(__name__)
@app.route('/admin')
def hello_admin():
   return 'Hello Admin'


@app.route('/guest/<guest>')

def hello_guest(guest):
   return 'Hello %s as Guest' % guest


@app.route('/user/<name>')
def hello_user(name):
   if name =='admin':
      return redirect(url_for('hello_admin'))
   else:
      return redirect(url_for('hello_guest',guest = name))


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

三、flask静态文件

1、可以在创建app的时候使用以下参数进行设置

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

参数作用
在视图中的Flask类中的参数作用:
1. template_folder 是存放页面的文件夹,默认是templates
2. static_folder 是静态文件夹的名字
3. static_url_path 是静态文件的路径,跟前端页面中的url路径一致

2 flask模板文件配置

(1) 模板文件修改代码演示,更改 template_folder 为 wangze

python代码部分
from flask import Flask,render_template

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


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


if __name__ == '__main__':
    app.run(port=4002,debug=True)
index.html部分
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1> hello world</h1>
</body>
</html>

(2)、发送请求: http://127.0.0.1:4002/index

image.png
3 flask静态文件配置(适用python3,python2会报错)
(1) python 代码部分
from flask import Flask, render_template

app = Flask(__name__)


@app.route("/")
def index():
    return render_template("hello.html")


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

(2) 与python代码同级目录templates/index.html部分
<!DOCTYPE html>
<html lang="en">

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

   <body>
      <img src="{{ url_for('static',filename='test2.jpg')}}" width="120" height="60"/> <br>
      <input type = "button" onclick = "sayHello()" value = "Say Hello" />
   </body>

</html>

(3) 与python代码同级目录static/js文件内容
function sayHello() {
   alert("Hello World")
}
(4) 目录结构,与templates同级目录
image.png
(5)demo:发送请求
image.png

四、flask模版方法

(1)demo.py

# encoding=utf-8
from flask import Flask, render_template

app = Flask(__name__)

user = {"username": "xiao xiao", "bio": "A girl who loves movies."}

movies = [
        {'name': 'My Neighbor Totoro', 'year': '1988'},
        {'name': 'Three Colours trilogy', 'year': '1993'},
        {'name': 'Forrest Gump', 'year': '1994'},
        {'name': 'Perfect Blue', 'year': '1997'},
        {'name': 'The Matrix', 'year': '1999'},
        {'name': 'Memento', 'year': '2000'},
        {'name': 'The Bucket list', 'year': '2007'},
        {'name': 'Black Swan', 'year': '2010'},
        {'name': 'Gone Girl', 'year': '2014'},
        {'name': 'CoCo', 'year': '2017'}
]


@app.route('/hi')
def hi():
    return "hello flask!"


@app.route("/watchlist")
def watchlist():
    return render_template("watchlist.html", user=user, movies=movies)


if __name__ == "__main__":
    app.run(debug=True,port=4001)


(2) templates/index.html 模版


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ user.username }}'s watchlist</title>
</head>
<body>

跳转到 h1方法 <br>
<a href="{{ url_for('hi') }}">← Return</a>


<h2>{{ user.username}}</h2>
{% if user.bio %}
    <i>{{ user.bio }}</i>
{% else %}
    <i>This user has not provided a bio.</i>
{% endif %}


{# 以下是电影清单(这是注释) #}
<h5>{{ user.username }}'s watchlist ({{ movies|length }}):</h5>
<ul>
    {% for movie in movies %}
        <li>{{ movie.name }} - {{ movie.year }}</li>
    {% endfor %}
</ul>


<hr>
{% for k,v in user.items() %}
    {{ k }} -- {{ v }} <br>
{% endfor %}

<hr>
{% if user.get('username') == "xiao xiao" %}
    {{user}}
{% endif %}


</body>
</html>



五、flask配置参数设置

1 demo.py

# -*- coding:utf8 -*-
import emoji
import random
from flask import Flask,current_app


app = Flask(__name__,template_folder='templates')

# 配置参数的使用形式
# 1 将配置写到配置文件中
app.config.from_pyfile('config.cfg')


# 2 使用对象配置参数
class Config(object):
   DEBUG = True
   ITCAST = 'python'


app.config.from_object(Config)

# 3 直接操作config字典对象
app.config['DEBUG'] = True


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

   # 读取配置参数
   # 1 直接从全局对象app的config字典中读取
   # print app.config.get('ITCAST')
   # 2 通过current_app获取config中的参数
   print current_app.config.get('ITCAST')

   # a = 1/0
   my_emoji = random.choice(emoji.EMOJI_UNICODE.keys())
   b = emoji.EMOJI_UNICODE.get(my_emoji)
   return '<h1>emoji is %s</h1>'%b


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

2 config.cfg文件内容

DEBUG = True

在同级目录下


image.png

六、flask蓝图

Why?
我们将所有的Flask请求方法都写在同一个文件下的话,非常不便于我们代码管理和后期功能代码的添加。比如:我们在一个文件中写入多个路由,这会使代码维护变得困难。

1 创建一个主的路由配置文件manage.py,该文件主要的作用就是启动整个的Flask框架(项目)

# -*- coding:utf8 -*-
from flask import Flask
from admin.admin import admin1 as admin_blueprint  # 导入蓝图
from front.front import front1 as front_blueprint  # 导入蓝图

app = Flask(__name__)


app.register_blueprint(admin_blueprint)  # 注册蓝图
app.register_blueprint(front_blueprint)  # 注册蓝图


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

2 在同级目录下创建 admin、front两个目录

mkdir admin && mkdir front 

目录结构如图(注意:admin.py及init.py文件在admin目录下):

image.png

3 admin.py 文件内容

# -*- coding:utf8 -*-
from flask import Blueprint, render_template

admin1 = Blueprint('admin', __name__, url_prefix='/admin')


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


@admin1.route('/register')
def register():
    return 'register'


@admin1.route('/login')
def login():
    return '<h1>login</h1>'

4 front.py 文件内容

from flask import Blueprint

front1 = Blueprint('front', __name__)


@front1.route('/add')
def add():
    return 'add'


@front1.route('/delete')
def delete():
    return 'delete'


七、flask表单扩展

1 表单扩展 test.py

# -*- coding:utf8 -*-
from flask import Flask,render_template
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,SubmitField
from wtforms.validators import EqualTo,DataRequired


app = Flask(__name__)
app.secret_key = '!@#T^@#!*#@#@!#@!#'


# 定义表单模型类
class RegisterForm(FlaskForm):
    # 自定义注册表单模型类
    # DataRequired 保证数据必须填写,且不能为空
    user_name = StringField(label=u'用户',validators=[DataRequired(u'用户名不能为空')])
    password = PasswordField(label=u'密码',validators=[DataRequired(u'密码不能为空')])
    password2 = PasswordField(label=u'确认密码',validators=[DataRequired(u'密码不能为空'),
                                                        EqualTo('password',u'两次密码不一致')])
    submit = SubmitField(label=u'提交')


@app.route('/register',methods =['POST','GET'])
def register():
    #
    form = RegisterForm()

    return render_template('register.html',form=form)


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

2 templates/register.html 内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>register</title>
</head>
<body>
    <form method="post" action="/register">
        {{ form.user_name.label }}
        <p>{{ form.user_name }}</p >
        {% for msg in form.user_name.errors %}
        <p>{{ msg }}</p >
        {% endfor %}

        {{ form.password.label }}
        <p>{{ form.password }}</p >
        {% for msg in form.password.errors %}
        <p>{{ msg }}</p >
        {% endfor %}

        {{ form.password2.label }}
        <p>{{ form.password2 }}</p >
        {% for msg in form.password2.errors %}
        <p>{{ msg }}</p >
        {% endfor %}

        {{ form.submit }}
    </form>
</body>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容