Python学习十二:Flask框架

一、Flask 简介

Flask 依赖两个外部库:WerkZeug 和 Jinja2。WerkZeug 是一个WSGI(在web应用和多种服务器之间的标准Python 接口)工具集。Jinja2负责渲染模板。所以在安装Flask之前,需要安装这两个外部库,而最简单的方法就是使用 Virtualenv 创建虚拟环境

1.1 安装虚拟环境

1.1.1 安装Virtualenv

pip install virtualenv 

检验

virtualenv --version

1.1.2 创建虚拟环境

下一步就是使用Virtualenv 命令在当前文件夹创建Python虚拟环境。创建虚拟环境之后当前文件夹会出现一个子文件夹,名字就是下述命令中指定的参数

virtualenv venv

在这里插入图片描述
在这里插入图片描述

1.1.3 激活虚拟环境

venv\Scripts\activate

1.2 安装Flask

pip install flask

安装校验

pip list --format columns

在这里插入图片描述

1.3 第一个Flask

from flask import Flask
app = Flask(__name__)

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

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

在这里插入图片描述
(1)首先我们导入了Flask类。这个类的实例将会是我们的WSGI应用程序
(2)接下来,我们创建了一个该类的实例,第一个参数是应用模块或者包名的名称。如果你还用单一的模块,比如本例,你应该使用__name__,因为模块的名称将会因其作为一个单独的应用模块启动还是作为模块导入而有不同(也是__main_或者实际的导入名)。这是必须得,这样Flask才知道到哪儿去模板,静态文件等。详情见Flask的文档。
(3)然后,我们使用route()装饰器告诉Flask什么样的URL能触发我们的函数
(4)这个函数的名字也在生成URL时被特定的函数采用,这个函数返回我们想要显示在用户浏览器中的信息
(5)最后我们使用run()函数来让应用运行在本地的服务器上面。其中if__name __=='__main__':确保服务器只会在该脚本被Python解释器直接执行的时候才会运行,而不是作为模板导入的时候

二、Flask基础

2.1 开启调试模式

虽然run()方法使用与启动本地的开发服务,但是用户没每次修改代码后需要手动的重启服务,这样并不优雅,而Flask可以做到更好。如果你启用了调试支持,服务器会在代码修改后自动重新载入,并且在发生错误的时候提供一个相当可用的调试器 相当于Java的热部署
使用方法,直接在代码中添加

 app.run(debug=True)
 或者
 app.debug=True
 app.run()

2.2 路由

处理URL和函数之间的关系的程序称之为路由

@app.route('/')
def hello_world():
    return '<h1>Hello World!</h1>'

在这里插入图片描述
修饰器是Python语言的标准特性,可以使用不同的方法修改函数的行为。惯常用法是使用修饰器把函数注册为事件的处理程序

2.2.1 变量规则

要给URL添加变量部分,你可以把这些特殊的字段编辑为<variable_name>,这个部分将会作为命名参数传递到你的函数。规格可以使用converter:variable_name指定一个可选的转化器

from flask import Flask
app = Flask(__name__)

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

@app.route('/user/<username>')
def show_user_profile(username):
    # 显示该用户名的用户信息
    return 'User %s' % username

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # 根据ID显示文章,ID是整型数据
    return 'Post %d' % post_id

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

  • int:接收整数
  • float:同int,但是接受的是浮点数
  • path:和默认的相似,但是也接受斜线

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2.2 构造URL

Flask能够匹配URL,而且还可以用url_for()来给指定的函数构造URL。它接收函数名作为第一个参数,也接受对应URL规则的变量部分的命名参数。未知变量部分会添加到URL末尾作为查询条件

from flask import Flask , url_for
app = Flask(__name__)

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

@app.route('/user/<username>')
def show_user_profile(username):
    # 显示该用户名的用户信息
    return 'User %s' % username

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # 根据ID显示文章,ID是整型数据
    return 'Post %d' % post_id

@app.route('/url/')
def get_url():
    # 根据ID显示文章,ID是整型数据
    return url_for('show_post',post_id=2)

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

在这里插入图片描述

2.2.3 HTTP方法

HTTP(与web应用会话的协议)有许多的不同的构造方法访问URL方法。默认情况下,路由只回应GET请求,当时通过route()装饰器传递methods 参数可以改变这个行为。

@app.route('/', methods=['GET', 'POST'])
def index():
	if request.methods=='POST':
		pass
	else:
		pass

在这里插入图片描述

2.3 静态文件

url_for('static',filename='style.css'),
# 这个文件应该存储在文件系统上的static/style.css

from flask import Flask, render_template

app = Flask(__name__)

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

@app.route('/user/<username>')
def show_user_profile(username):
    # 显示该用户名的用户信息
    return render_template('user.html', name=username)

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

在这里插入图片描述

在这里插入图片描述

2.4 蓝图

蓝图学习
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、模板

模板是一个包含响应文本的额文件,其中包含用占位变量表示的动态部分,其具体值只在请求的上下文中才能知道。使用真实值替代变量,再返回最终得到的响应字符串,这一过程称为渲染。为了渲染模板,Flask使用了一个名为Jinja2的强大模板引擎

3.1 渲染模板

默认情况下,Flask在程序文件夹中的templates 子文件夹中寻找模板。

比如:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3.2 变量

我们可以在模板中使用变量{{name}},这表示一个占位符,而name是变量名称;
模板学习

<p>从一个字典中获取一个值:{{mydict['key']}}.</p>
<p>从一个列表中获取一个值:{{mylist[3]}}.</p>
<p>从一个列表中获取一个带索引的值:{{mylist[myintvar]}}.</p>
<p>从一个对象的方法中获取一个值:{{myobj.somemethod()}}.</p>

可以使用过滤器修改变量,过滤器添加变量名之后,中间使用竖线分隔。

Hello,{{name|capitalize}}

Jinja2提供了许多内置过滤器,常用的过滤器如下:
在这里插入图片描述
在这里插入图片描述

3.3 控制结构

3.3.1 条件控制语句

if…else…endif

{% if user %}
Hello,{{user}}
{% else %}
Hello Stranger
{% endif %}

3.3.2 循环语句

{% for comment in comments %}
{{comment}}
{% endfor %}

3.3.3 宏

宏类似于Python代码中的函数

{% macro render_comment(comment) %}
{{comment}}
{% endmacro  %}

{% for comment in comments %}
{{render_comment(comment)}}
{% endfor %}

3.3.4 公共代码

需要在多处重复使用的模板代码片段可以写在独立的文件,在包含在所有的模板中,以免重复
方法一:全部包含

{% include 'common.html' %}

方法二:继承包含
base.html

<html>
<head>
{%block head%}
<title>{%block title%}{%endblock%}-My Application</title>
<%endblock%>
</head>
<title>
<body>
{%bolck body%}
{%endbody%}
</body>
</html>


bolck标签定义的元素可在衍生模板中修改。在本例中,我们定义了名为head、title、body的块。注意。title包含在head中。

举例衍生模板

{% extends "base.html"}
{%block title%}Index{%endhead%}
{%block head%}
{{supper()}}
<style>
</style>
{% endblock %}
{%bolck body%}
<h1>Hello</h1>
{%endbody%}

extends 指令声明这个模板衍生于base,html,在extends指令之后,基模板的三个块被重新定义,模板引擎将会在其插入适当的位置,注意新定义的head块,在基模板中其内容不是空的,所以用supper()获取原来的内容

四、Web表单

  • web表单是允许用户和web应用交互的基本元素,FLask自己是不会处理表单的,但是Flask-WTF扩展允许用户在flask应用中使用著名的WTForms包,这个包使得定义表单和处理表单变得简单
    参考

4.1 安装

pip install flask-wtf

安装成功显示如下:
在这里插入图片描述

4.2 CSRF的保护和验证

官网

CSRF跨站请求伪造,源于WEB的隐式身份验证机制。WEB的身份验证机制虽然可以抱着一个请求时来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。

例如,用户登录受信任的网址A,在本地生成了Cookie,在Cookie没有失效的情况下去访问了危险网站B。B可能会盗用你的身份,以你的名义去发送恶意请求,邮件,盗取你的账号,设置购买商品,造成你个人隐私泄露,已经财产安全。

实际上,WTForms在渲染没一个表单都会生成一个独一无二的token,这个token将在POST请求的时候随着表单一起提交进行验证。默认情况下Flask-WTF能保护所有表单免受跨域请求伪造的攻击,恶意网站把请求发送到被攻击者已经登陆的网站就会引发CSRF攻击。为了实现CSRF保护,Flask-WTF需要程序设置加密令牌,再用加密令牌来验证表单数据的真伪。

使用方法

app = Flask(__name__)
app.config['SECRET_KEY'] = 'abcd123'
  • app.config字典可以存储框架、扩展和程序本身的配置变量。使用标准的字典语法把配置值添加到app.config对象中
  • SECRET_KEY配置变量是通用密钥,可在Flask和多个扩展中使用

4.3 表单类

使用Flask-WTF时,每个表单都由一个继承自Form的类表示,这个类定义表单中的一组字段。

每个字段有用对象表示,并且字段可以附属一个或者多个校验用来验证用户输入的数据是否符合要求。

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import Required
class NameForm():
    name = StringField('请输入姓名', validators=[Required()])
    password = PasswordField('请输入密码', validators=[Required()])
    submit = SubmitField('Submit')

这个表单中所有字段都定义为类变量,类变量的值是相应字段类型的对象
在这里插入图片描述
在上述代码中我们使用了三个HTML标准字段,更多参考如下:
在这里插入图片描述
在这里插入图片描述

4.4 把表单渲染成HTML

表单字段是可调用的,在模板中渲染会生成HTML。

假设视图函数把一个NameForm实力通过参数传进form表单,在模板中可以生成一个简单的表单验证用户登录信息。

创建一个model.py文件定义一个表单类LoginForm,其中有三个属性分别是name,password和submit,具体代码如下:

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField,SubmitField
from wtforms.validators import DataRequired,Length
 
class LoginForm(FlaskForm):
    """
    登录表单类
    """
    name = StringField(label='用户名', validators=[
        DataRequired("用户名不能为空"),
        Length(max=10,min=3,message="用户名长度必须大于3且小于8")
    ])
    password = PasswordField(label='密码', validators=[
        DataRequired("密码不能为空"),
        Length(max=10, min=6, message="用户名长度必须大于6且小于10")
    ])
    submit = SubmitField(label="提交")

在文件中分别创建首页视图index()函数和登录页视图login()函数。引入我们刚才创建的model.py文件并在login()视图函数中对用户登陆进行验证,验证通过则跳转至首页,否则提示错误

from flask import Flask ,url_for,redirect, render_template
from models import LoginForm
 
app = Flask(__name__)
app.config['SECRET_KEY'] = 'mrsoft'
 
 
@app.route('/login', methods=['GET', 'POST'])
def login():
    """
    登录页面
    """
    form = LoginForm()
    if form.validate_on_submit():
        username = form.name.data
        password = form.password.data
        if username== "admin" and password == "abcd1234":
            return redirect(url_for('index'))
    return render_template('login.html',form=form)
 
@app.route('/')
def index():
    """
    首页
    """
    name = "班德尔城"
    message = """
        约德尔人的故乡究竟在何处?对于这个问题人们众说纷纭,不过有一些凡人声称自己穿过了无形的传送门,进入了超越物质领域的奇异魔法世界。他们都描述了一个魔法奔放的地方,鲁莽蛮横的人会被无数的奇观带入歧途,最后迷失在梦境中,永远无法返回……
在班德尔城,任何约德尔人以外的种族都会感到自己的全部感官得到了强化。城中所见无不色彩斑斓,食物与水的味道让人经年沉醉——只要尝过一次,就终身难忘。这里日光溶溶,春水不休,每一株植物都会结出累累硕果。或许这些描述中有一部分属实,或许全都是假的——因为没有任何两个讲述者能够对所见所闻达成一致。
只有一件事可以肯定,那就是班德尔城和里面的居民都具有某种超脱时间的属性,这或许可以解释为什么从那里回来的凡人全都像是一夜苍老了许多年岁,更多人则根本是一去不复返。
    """
    return render_template("index.html",name=name,message=message)
 
if __name__ == '__main__':
    app.run(debug=True,
            port=8000)

渲染login.html和index.html如下:


<div class="jumbotron">
  <form action="" method="post">
      <div class="form-group">
      {{ form.name.label }}
      {{ form.name(class="form-control")}}
      {% for err in form.name.errors %}
          <p style="color: red">{{ err }}</p>
      {% endfor %}
      </div>
      <div class="form-group">
      {{ form.password.label }}
      {{ form.password(class="form-control") }}
      {% for err in form.password.errors %}
         <p style="color: red">{{ err }}</p>
      {% endfor %}
      </div>
      {{ form.csrf_token }}
      {{ form.submit(class="btn btn-primary") }}
  </form>
</div>

<div class="jumbotron">
  <h1 class="display-3">欢迎来到{{name}}</h1>
  <p >
      {{message}}
  </p>
  <hr class="my-4">
  <p>
    <a class="btn btn-primary btn-lg" href="#" role="button">了解更多</a>
  </p>
</div>

当我们运行run.py函数,浏览器输入

http://127.0.0.1:5000/login

在这里插入图片描述
如果用户没有填入值就直接提交,DataRequired就会捕获这个异常

在这里插入图片描述
如果用户密码长度不满足要求,length()函数就会捕获这个异常
在这里插入图片描述
密码输入无误,则会成功跳转至首页
在这里插入图片描述

  • 7
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码浪人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值