玩命加载中 . . .

Flask基础


第一个程序

Flask是基于Python的web开发框架。

从最基本的Flask代码开始吧:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
   return 'Hello World'

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

运行如上代码,就可以在浏览器中看到运行结果——Hello,Flask!

  • 第二行调用Flask()构造函数,返回的是一个application对象;
  • url ‘/‘绑定到了hello_world()上面;
  • 在上面的示例中,run()方法用于在本地服务器上运行应用程序,其函数原型为:
    app.run(host, port, debug, options)

  • host,指定主机端口号

  • port,端口号
  • debug,是否启用调试模式

Flask路由

在Web应用中,不同的url对应不同的页面;Flask中的route()装饰器用于将URL绑定到函数:

from flask import Flask
app = Flask(__name__)

@app.route('/hello')
def hello_flask():
    return 'hello Flask'

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

在上面的代码示例中,route()装饰器将URL‘/hello’规则绑定到了hello_flask()函数,如果用户访问
http://localhost:5000/hello ,hello_flask()函数的输出就将在浏览器中呈现。

当然,也可以不使用装饰器写法,改用application对象的add_url_rule()函数也可以实现URL与函数的绑定:

def hello_flask():
    return 'hello flask!'
app.add_url_rule('/', 'hello', hello_flask)

Flask变量规则——路由参数

向规则参数添加变量部分,可以动态地构建URL。
此变量部分标记为 < variable-name >
示例:

@app.route('/blog/<int:postId>')
def show_blog(postId):
    return 'Blog Number %d' % postId

@app.route('/rev/<float:revNo>')
def revision(revNo):
    return 'Revision Number %f' % revNo

< int:postId>中,int是对变量类型postId的限制,我们在地址栏中输入/blog/9后,按下回车,屏幕上就会显示Blog Number 9。

  • %d 整型
  • %f 浮点型
  • %s 字符串型

Flask URL构建

函数url_for(),用于动态构建特定函数的URL。

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_adminn'))
    else:
        return redirect(url_for('hello_guest', guest=name))

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

在/user/…对应的函数hello_user中,我们作出了处理:
如果接收参数为字符串admin,就重定向到hello_admin()函数否则重定向到hello_guest()函数。

Flask中的HTTP

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <form action="http://localhost: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>

我们创建一个html文件,在其中写一个表单,在下面的文件中接收表单提交到服务器的数据。

# 在Flask中使用HTTP方法
from flask import Flask, redirect, url_for, request

app = Flask(__name__)

@app.route('/success/<name>')
def success(name):
    return 'welcome %s' % name

@app.route('/login', methods=['POST', 'GET'])
def login():
    if request.method == 'POST':
        # 通过表单拿到输入的名字,并给动态URL
        user = request.form['nm']
        return redirect(url_for('success', name=user))
    else:
        user = request.args.get('nm')
        return redirect(url_for('success', name=user))

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

模板

模板的来历

之前与URL绑定的函数,叫做视图函数,一般来说,视图函数有两个作用:

  • 处理业务逻辑(背后的业务代码,也即展示出来的数据是怎么来的)
  • 返回相应内容(将要展示的数据表现出来)

在大型应用中,一般选择将业务逻辑与表现内容分开,否则代码极其复杂,维护起来很困难。
因此,我们需要用到模板。

何为模板

模板,其实就是一个包含响应文本的文件,特殊的地方在于,里面有动态文本内容,使用占位符变量来表示,占位符变量可以告诉模板引擎该处的值需要从另外的地方获取数据;
另外,从视图函数中的真实值,替换模板中的占位符变量,这个过程简单理解为“渲染”。
如此一来,模板的使用,就可以将业务逻辑与表现内容分离开来,使得

  • 视图函数只负责业务逻辑和数据处理
  • 模板只负责从视图函数中获取数据进行展示

举例:
我们在项目中单独创建templates文件夹,并在该目录下创建一个模板文件hello.html;

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>05_Flask模板</title>
</head>

<body>
    我的模板html内容
    <!-- 注意,以下的双括号插值都是待加入的变量,从视图函数中得来 -->
    <br />{{ my_str }}
    <br />{{ my_int }}
    <br />{{ my_array }}
    <br />{{ my_dict }}
</body>

</html>

可以发现,模板文件中,占位符处的值需要从视图函数中获取对应的数据,下面是视图函数所在文件:

from flask import Flask, render_template
from sympy import deg

app = Flask(__name__)

# 我们向模板中传入字符串、列表、字典
@app.route('/')
def index():
    # 定义要往模板中传递的数据
    my_str = 'Hello World'
    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(debug=True)

控制代码块写法

包括if写法(选择)、for写法(循环)。
演示相关的模板语法:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!-- 模板语法,使用{# #}表示注释 -->
    {# 判断显示内容 #}
    {% if name %}
    <!-- janjo模板语法,双括号插值写法,|后面跟一个函数(首字母大写) -->
    <h1>hello {{ name|capitalize }}</h1>
    {% else %}
    <h1>请登录</h1>
    <!-- 选择代码块的结束标识 -->
    {% endif %}

    <!-- for循环的使用 -->
    {% for general in my_list %}
        {{ general }} <br/>
    <!-- 循环代码块的结束标识 -->
    {% endfor %}
</body>
</html>

视图函数如下:

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/control')
def control():
    my_list = ['徐达', '常遇春', '郭英', '蓝玉', '傅友德', '耿炳文']
    return render_template('control.html', name='xiaoming', my_list=my_list)

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

过滤器

过滤器的本质就是函数。它的作用在于“微调”,即有时候我们需要对模板中的数据做一定的修改,比如更改格式(首字母大写、日期格式等),在模板中自然不能直接调用Python方法,这样一来,就需要用到过滤器。
语法格式如下:

{{ variable | filter_name(*args) }}
variable即为变量,filter_name即为过滤器函数,*args 为过滤器接收的参数
常见的内置过滤器有

  • upper:字符串中全部字符大写
  • lower:字符串中全部字符小写
  • reverse:字符串反转
  • format:格式化输出
  • first:取列表的首元素
  • last:去列表的尾元素
  • length:得到列表长度
  • sum:得到列表所有元素之和
  • sort:列表排序

等等。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    {% for item in my_list %}
    <!-- upper为过滤器,表示将变量item全部大写 -->
        {{ item | upper }}
    {% endfor %}
</body>
</html>
from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def show_filter():
    my_list = ['www', 'wanda', 'amazi']
    return render_template('filter.html', my_list=my_list)

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

Flask Request对象

来自客户端网页的数据作为全局请求对象发送到服务器,为了处理请求数据,应该从Flask模块导入。

Request对象的重要属性如下:

  • Form:字典对象,包含表单参数及其值的键、值;
  • args:解析查询字符串的内容,URL中?之后的部分;
  • Cookies:保存Cookie名称和值的字典对象;
  • files:与上传文件有关的数据;
  • method:当前的请求方法

Web表单

web表单是web应用程序的基本功能。在Flask中,为了处理web表单,我们一般使用Flask-WTF扩展,它封装了WTForms,并且有验证表单数据的功能。

from curses import flash
from flask import Flask, render_template, request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    # request对象,里面包含请求的信息,包括请求方式
    if request.method == 'POST':
        # 获取表单数据
        form = request.form
        username = form.get('username')
        password = form.get('password')
        print(password)
        if not all([username, password]):
            # print('参数不完整')
            # 使用消息闪现
            flash('参数不完整')
        elif password != '123':
            # print('密码错误...')
            flash('密码错误!')
        else:
            return 'success'
    return render_template('login.html')

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

消息闪现flash

在上面的栗子中,我们使用了flash,它代替了print语句,也可以传递消息。

  • 视图函数中,我们使用flash,其中参数就是消息内容字符串
  • 模板中,使用for循环遍历获取闪现消息

表单数据发送到模板

原生写法

有了前面的知识点,我们接下来研究如何将表单数据发送到模板。
我们的案例中,准备了两个模板文件student.html(收集表单数据)、result.html(展现收集到的表单数据,以表格形式)。

<!-- student.html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <form action="http://localhost:5000/result" method="POST">
        <p>Name <input type="text" name="Name" /></p>
        <p>Physics <input type="text" name="Physics" /></p>
        <p>Chemistry <input type="text" name="chemistry" /></p>
        <p>Maths <input type="text" name="Mathematics" /></p>
        <p><input type="submit" value="submit" /></p>
    </form>
</body>

</html>
from flask import Flask, render_template, request

app = Flask(__name__)

# 首先进入/ URL页面,呈现具有表单的网页
@app.route('/')
def student():
    return render_template('student.html')

@app.route('/result', methods=['POST', 'GET'])
def result():
    if request.method == 'POST':
        # 收集字典对象中的request.form中的表单数据,并给result.html
        result = request.form
        return render_template('result.html', result=result)

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

由于student()绑定到URL /页面下,因此首先展示的就是student()中渲染的student.html文件,即展示表单;
而一旦有提交表单的POST请求,就会将请求中的表单数据给模板result.html来渲染。
result.html文件如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <table border=1>
        {% for key, value in result.items() %}
        <tr>
            <th> {{ key }} </th>
            <td> {{ value }}</td>
        </tr>
        {% endfor %}
    </table>
</body>

</html>

WTF

基本使用

Flask的WTF表单,提供了更加方便的写法:

from flask import Flask, render_template, request, flash
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField

app = Flask(__name__)
app.secret_key = 'itheima'  # 设置加密密钥

'''
使用WTF实现表单
自定义一个表单类LoginForm
'''

class LoginForm(FlaskForm):
    username = StringField(u'用户名:')
    password = PasswordField(u'密码:')
    submit = SubmitField(u'提交:')


@app.route('/', methods=['GET', 'POST'])
def login():
    login_form = LoginForm()
    return render_template('wtf.html', form=login_form)


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

模板文件wtf.html内容如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <form action="">
        {{ form.username.label }} {{ form.username }}
        {{ form.password.label }} {{ form.password }}
        {{ form.submit.label }} {{ form.submit }}
    </form>
</body>

</html>

在视图函数所在的.py文件,导入所需要的库之后,需要单独定一个类,并定义出表单所有项,然后将该类的实例对象给渲染函数,便于模板文件中使用。
在模板文件中,我们用FlaskForm继承类的表单项来获取相应的组件,通过其label属性来获取文本标签。可见上面.html栗子。

表单验证

# 开启wtf验证
@app.route('/', methods=['GET', 'POST'])
def login():
    login_form = LoginForm()
    # 判断请求方式
    if request.method == 'POST':
        # 获取请求参数
        form = request.form
        username = form.get('username')
        password = form.get('password')
        # 验证参数,WTF可以一句话实现所有的校验
        if login_form.validate_on_submit():
            return 'success!'
        else:
            flash('参数有误!')

    return render_template('wtf.html', form=login_form)

在Flask中使用数据库

Request对象包含Cookie的属性

Flask Session


文章作者: 鹿卿
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 鹿卿 !
评论
  目录