Python-Flask 视图和模板(4)

一、视图(V)

视图是一个应用对请求进行响应的函数。 Flask 通过模型把进来的请求 URL 匹配到 对应的处理视图。视图返回数据, Flask 把数据变成出去的响应。 Flask 也可以反 过来,根据视图的名称和参数生成 URL 。

返回值:其实返回值返回的都是一个响应对象,底层将返回的字符串包装成一个response对象。其实就是底层的Response父类的default-minetype设置成text/html类型,用户看到的就是网页内容。
在这里插入图片描述

1.response响应对象

视图函数的返回值会自动转换为一个响应对象。如果返回值是一个字符串,那么会被转换为一个包含作为响应体的字符串、一个 200 OK 的状态代码 和一个 text/html 类型的响应对象(response对象)。返回值的类型其实不只仅仅有字符串类型,还支持返回字典,元组,响应对象,WSGI回调函数(# The return type must be a string, dict, tuple, Response instance, or WSGI callable)。

  • 如果视图返回的是一个响应对象,那么就直接返回它。

  • 如果返回的是一个字符串,那么根据这个字符串和缺省参数生成一个用于返回的 响应对象。

    • 如果视图函数单纯返回"****"的字符串的话,flask会自动进行一些封装让他变成浏览器可以读取的格式,也就是content-type = text/html,状态码为200。
  • 如果返回的是一个字典dict,那么它会被转换为一个 JSON 响应。

    • 如果字典还不能满足需求,还需要创建其他类型的 JSON 格式响应,那么调用 jsonify()创建一个响应对象,该函数会序列化任何支持的 JSON 数据类型。。
  • 如果返回的是一个元组,那么元组中的项目可以提供额外的信息。元组中必须至少 包含一个项目,且项目应当由 (response, status) 、 (response, headers) 或者 (response, status, headers) 组成。 status 的值会重载状态代码, headers 是一个由额外头部值组成的列表 或字典。

  • 如果以上都不是,那么 Flask 会假定返回值是一个有效的 WSGI 应用并把它转换为 一个响应对象。

如果想要在视图内部掌控响应对象的结果,也就是响应头的信息不满足你的需求,需要在响应头中添加额外的信息,或者想要返回一个字符串页面内容,那么可以使用 make_response() 函数。
在这里插入图片描述
假设有如下视图:

@app.errorhandler(404)
def not_found(error):
    return render_template('error.html'), 404

可以使用 make_response() 包裹返回表达式,获得响应对象,并对该对象 进行修改,然后再返回:

@app.errorhandler(404)
def not_found(error):
    resp = make_response(render_template('error.html'), 404)
    resp.headers['X-Something'] = 'A value'
    return resp
@app.route('/index4')
def index4():
    content = '''
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
    <style>
        div{
            width: 100%;
            height: 100px;
            border: 2px solid red;
        }
    </style>
</head>
<body>
<h1>欢迎来到京东购物网站</h1>
<div>
    <ul>
        <li>hello</li>
        <li>abc</li>
        <li>world</li>
    </ul>
</div>

</body>
</html>
    '''
    response = make_response(content)  # 返回值就是一个response对象
    # 定制响应头
    response.headers['mytest'] = '123abc'
    response.headers['myhello'] = 'hellohello'
    # 将定制好的response返回

    return response

总结:
(1)什么时候需要使用make_response?
当返回一个视图的时候,需要定制响应头,则可以使用make_response()包裹相应信息。

(2)response对象常用的属性与方法:

print(response.content_type)
print(response.headers)
print(response.status_code)  # 200
print(response.status)  # 200 OK

(3)视图函数的返回值,response响应:

  • str 自动转成response对象
  • dict json
  • response对象 response对象
  • make_response() response对象
  • redirect() 重定向 302状态码
  • render_template() 模板渲染 + 模板

2.request请求对象

只需要导入,通过from flask import request,导入之后可以获取对象的属性和方法。

属性:
print(request.headers) # request对象 对象访问属性,也可以调用方法
print(request.path)
print(request.full_path)
# 获取到提交的参数内容,例如get形式提交表单
# /register2?username=zhangsan&address=Beijing
print(request.base_url)
print(request.url)

跟请求方法相关的: 获取页面提交的内容
(1)get:
request.args 底层是字典的形式 主要获取get提交的请求参数
如果是get请求格式是这个样子的:/register2?username=zhangsan&address=Beijing
此时的username是form表单中表单元素的name值

	print(request.args)  # dict类型  d = {'a':'aaa','b':'7878'}  d.get('b')  只能取到get请求的
    print(request.args.get('username'))   # 获取值
    print(request.args.get('address'))

(2)post:
request.form 底层是字典的形式 主要获取post提交的请求参数
注意post提交必须在路由中进行设置,通过methods = [‘GET’,‘POST’]
按照此种形式:

    @app.route('/register2', methods=['GET', 'POST'])
    def register2():  # 获取页面提交的内容
        .......  内容省略
    获取数据:
    print(request.form)  # 如果请求方法是post,则需要通过request.form取值
    print(request.form.get('username'))
    print(request.form.get('address'))

二、模板

1.返回模板文件

如果想在视图函数中获取模板xxx.html的内容则通过render_template()

render_template(‘模板名称’) 返回值是一个字符串,主要是通过模板引擎(Jinjia2)去找到文件并将模板内容转成字符串的形式。
在这里插入图片描述

@app.route('/register')
def register():
    return render_template('register.html')  # 默认去模板文件夹中找模板文件。

疑问:怎么知道哪个文件时模板文件夹?
答:创建Flask对象的时候,有一个template_folder参数设置成了template,声明好了模板文件夹,就回去这里指定的文件里面找模板文件了。

2.重定向+url_for(路径反向解析)

redirect(‘/’)实现重定向,两次响应。但是如果在项目中,会有很多路径或者路径比较长,不易记,所以可以使用url_for来指定endpoint(在路由的装饰器上添加endpoint),去访问真正的路径。

url_for有两种使用方式:

  • 如果路由有配置endpoint的话,那么url_for的参数直接使用endpoint来反向解析路径
  • 如果没有配endpoint的话,就填写函数名,url_for会根据函数名去反向解析路径
    • 注意:如果路由是注册在蓝图上的话,函数名前需要 指定蓝图的名字,以蓝图名.函数名的形式作为url_for的参数
@app.route('/', endpoint='index')
def index():
    return render_template('index.html')

@app.route('/register', methods=['GET', 'POST'])
def register():
    print(request.method)
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        repassword = request.form.get('repassword')
        # 用户密码一致性验证
        if password == repassword:
            # 保存用户
            user = {'username': username, 'password': password}
            users.append(user)
            return redirect(url_for('index'))  # 有两次响应:1。302状态码 + location  2。 返回location请求地址内容
        else:
            return '两次密码不一致'

    return render_template('register.html')

@app.route('/show')
def show():
    # users[] ----> str''   json字符串
    j_str = json.dumps(users)
    return j_str


@app.route('/test')
def test():
    url = url_for('index')  # 路径反向解析
    print(url)  # /
    return 'test'

3.模板的语法

如果需要传值到模板页面中,渲染在页面上显示的话,可以在视图函数中返回的时候添加参数,例如:return render_template(‘show_1.html’, girls=girls, users=users)
(1)在模板中获取view中传递的变量值:{{ 变量名}},类似于vue中使用mastache语法,也叫双大括号语法显示变量值。变量值支持字符串、列表、元组、set、对象等常用的数据类型

render_template(‘模板名字’,key=value,key=value)

@app.route('/show')
def show():
    name = 'xzz'  # str
    age = 18  # int
    friends = ['迪丽热巴', 'cr', '任嘉伦']  # list
    dict1 = {'gift': 'YSL', 'gift1': '鲜花', 'gift2': '包包'}  # dict
    # 创建对象
    girlfriend = Girl('cr', 'mz')   # 自定义的类构建的类型:Girl对象
    return render_template('show.html', name=name, age=age, gender='男', friends=friends, dict1=dict1, girl=girlfriend)

模板文件显示内容:

<div>用户信息展示</div>
<p>
    用户名是:{{ name }} -- {{ age }} ---{{ gender }}
    <br>
    {{ friends.0 }}
    <br>
    {{ dict1.get('gift') }} --- {{ dict1.gift1 }}
    <br>
    {{ girl.gender }} -- {{ girl.name }} -- {{ girl.addr }}
</p>

在这里插入图片描述

模板文件获取值的一些简化写法:
{{ list.0 }} 同 {{ list[0] }}
{{ dict.key }} 同 {{ dict.get(key) }}
{{ girl.name }} 同 {{ 对象.属性 }}

(2)控制块:
if语句

 {% if  条件 %}

 {% endif %}

 {% if  条件 %}
     条件为True
 {% else %}
     条件为False
 {% endif %}
<ul>
    {% for girl in girls %}
        {# |相当于过滤器 #}
        {% if girl|length >= 3 %}
            <li class="a"> {{ girl }}</li>
        {% else %}
            <li>{{ girl }}</li>
        {% endif %}
    {% endfor %}
</ul>

在这里插入图片描述

for语句

 {% for 变量 in 可迭代的对象 %}
    for循环要做的任务

 {% endfor %}

for循环还有一个loop变量,通过该变量可以获取到数据的下标(序号):
loop.index 序号从1开始
loop.index0 序号从0开始

loop.revindex reverse 序号是倒着的
loop.revindex0

loop.first 布尔类型 是否是第一行
loop.last 布尔类型 是否是第二行

<table border="1" cellpadding="0" cellspacing="0" width="50%">
    {% for user in users %}
        <tr {% if loop.index == 3 %} style="background-color: deeppink" {% endif %}>
            <td> {{ loop.index }}</td>
            <td>{{ user.username }}</td>
            <td>{{ user.password }}</td>
            <td>{{ user.addr }}</td>
            <td>{{ user.phone }}</td>
        </tr>
    {% endfor %}
</table>

在这里插入图片描述

4.过滤器

过滤器的本质就是函数,模板语法中过滤器:
{{ 变量名 | 过滤器(*args) }}

{{ 变量名 | 过滤器 }}

(1)常见的过滤器:

1.safe : 禁用转译
msg = '<h1>520快乐!</h1>'
return render_template('show_2.html', girls=girls, users=users, msg=msg)
不想让其转译:
{{ msg | safe }}

2.capitalize:单词的首字母大写
{{ n1 | capitalize }}

3.lower和upper
大小写的转换

4.title 一句话中每个单词的首字母大写
 msg = 'She is a beautiful girl'
 {{ msg | title}}
 
5.reverse  翻转
{{ n1 | reverse}}

6.format
{{ '%s is %d years old' | format('cr',18) }}

7.truncate 字符串截断

(2)list的操作:

{# 列表过滤器的使用 #}
{{ girls | first }}<br>
{{ girls | last }}<br>
{{ girls | length }}<br>
{#{{ girls | sum }} 整型的计算 #}
{{ [1,3,5,7,9] | sum }}<br>
{{ [1,8,5,7,3] | sort }}<br>

(3)dict

{% for v in users.0.values() %}   ---->获取值
    <p>{{ v }}</p>
{% endfor %}

<hr>
{% for k in users.0.keys() %}   ----》获取键
    <p>{{ k }}</p>
{% endfor %}

<hr>

{% for k,v in users.0.items() %}  ---》获取键值
    <p>{{ k }}---{{ v }}</p>
{% endfor %}

(4)自定义过滤器:

  • 通过flask模块中的add_template_filter方法
    a. 定义函数,带有参数和返回值
    b. 添加过滤器 app.add_template_filter(function,name=‘’)
    c. 在模板中使用: {{ 变量 | 自定义过滤器 }}
  • 使用装饰器完成
    a. 定义函数,带有参数和返回值
    b. 通过装饰器完成,@app.template_filter(‘过滤器名字’)装饰步骤一的函数
    c. 在模板中使用: {{ 变量 | 自定义过滤器 }}

5.模板复用

(1)模板继承
需要模版继承的情况:

  • 多个模板具有完全相同的顶部和底部
  • 多个模板具有相同的模板内容,但是内容中有部分不一样
  • 多个模板具有完全相同的模板内容

模板复用标签:
{% block 名字 %}

{% endblock %}


模板复用的实现思路: 1.定义父模板 2.子模板继承父模板

实现步骤:

  • 父模板:

    • 定义一个base.html的模板,也就是父模板
    • 分析模板中哪些是变化的,变化的部分用模板的复用标签block做个占位。比如:{% block title %}父模板的title{% endblock %}
    • 注意:样式和脚本 需要提前预留。否则在子页面中只有继承自父模板的样式以及脚本,加上子页面的样式和脚本无法生效。也就是说子页面只能在block标签里面添加style,script这些内容。
      {% block mycss %}{% endblock %}
      {% block myjs %}{% endblock %}
  • 子使用父模板:

    • {% extends ‘父模板的名称(html文件名)’ %}将父模板继承过来
    • 找到对应的block(坑)填充,每一个block都是有名字的。
#如果需要引入外部文件,比如说引入样式文件,脚本文件等公共的文件。url_for默认只有一个参数,就是static,filename是关键字参数,必须要加上filename关键字才能成功访问。
 <link rel="stylesheet" href="{{ url_for('static',filename='css/style.css') }}">

include: 包含,在A,B,C页面都共同的部分,但是其他页面没有这部分,这个时候考虑使用include。

步骤:

  • 先定义一个公共的模板部分,xxx.html
  • 谁使用则include过来, {% include ‘文件夹/xxx.html’ %}

6.宏:macro

(1)把它看作是jinja2的一个函数,这个函数可以返回一个HTML字符串
(2)目的:代码可以复用,避免代码冗余

定义两种方式:

  • 在模板中直接定义:
    {% macro 函数声明 %} 函数体 {% endmacro %}
{#  定义宏  #}
{% macro form(action,value='登录',method='post') %}
    <form action="{{ action }}" method="{{ method }}">
        <input type="text" placeholder="用户名" name="username">
        <br>
        <input type="password" placeholder="密码" name="password">
        <br>
        <input type="submit" value="{{ value }}">
    </form>
{% endmacro %}

{# 调用宏 #}
{{ form('/') }}
  • 将所有宏提取到一个模板中(macro.html),哪里需要哪里导入,推荐使用这种方式定义宏,维护性比较好。
    {% import ‘macro.html’ as xxx %}
    {{ xxx.宏名字(参数) }}
# 将需要复用的宏单独放到一个文件中,哪里需要就导入调用即可。
{% macro form(action,value='登录',method='post') %}
    <form action="{{ action }}" method="{{ method }}">
        <input type="text" placeholder="用户名" name="username">
        <br>
        <input type="password" placeholder="密码" name="password">
        <br>
        <input type="submit" value="{{ value }}">
    </form>
{% endmacro %}

# 在其他文件中使用
{% import 'macro/macro.html' as func %}
{{ func.form('/welcome',value='注册') }}

三、总结

(1)变量: {{ 变量 }}
(2)块:
成对出现
{% if 条件 %} …{% endif %}
{% for 条件 %} …{% endfor %}
{% block 条件 %} …{% endblock %}
{% macro 函数声明 %} 函数体 {% endmacro %}

单个出现
{% include ‘’ %} 包含
{% import ‘’ %} 导入宏
{% extends ‘’ %}

函数/宏使用
{{ url_for(‘static’,filename=‘’) }}
{{ hongname(xxx) }}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值