Python_Flask系列_3.视图,模板

前言

学习参考

一、视图

第一个Flask程序

from flask import Flask
app = Flask(__name__)#Flask类接收一个参数__name__

@app.route('/')# 装饰器的作用是将路由映射到视图函数index
def hello_world():
    return 'Hello World'
    
if __name__ == '__main__':# Flask应用程序实例的run方法启动WEB服务器
    app.run(debug=True)

路由系统

● @app.route('/user/')
● @app.route('/post/int:post_id')
● @app.route('/post/float:post_id')
● @app.route('/post/path:path')
● @app.route('/login', methods=['GET', 'POST'])

# 路由传递的参数默认当做string处理,这里指定int,尖括号中冒号后面的内容是动态的
@app.route('/user/<int:id>')
def test(id):
	abort(404)#如果abort函数被触发,其后面的语句将不会执行
    return 'test %d' %id,999#return后面可以自主定义状态码(即使这个状态码不存在)。
#重定向redirect
@app.route('/',methods=['GET', 'POST'])
def test1():
    #return redirect('http://www.baidu.com')
    return redirect(url_for('test',_external=True))#url_for()接收视图函数名作为参数,返回对应的URL;
#通过装饰器来实现捕获异常    
@app.errorhandler(404)
def error(e):
    return f'您请求的页面不存在了,请确认后再次访问!{e}'
#@app.errorhandler(404)
#def page_not_found(e):
#    return render_template('404.html'), 404
@app.route('/')
def hello_itcast():
    return render_template('index.html')
@app.route('/user/<name>')
def hello_user(name):
    return render_template('index.html', name=name)

二、模板

  • Jinja2
    Jinja2:是 Python 下一个被广泛应用的模板引擎,是由Python实现的模板语言,他的设计思想来源于 Django 的模板引擎,并扩展了其语法和一系列强大的功能,其是Flask内置的模板语言。

1.模板的基本语法

渲染模版函数
● Flask提供的 render_template 函数封装了该模板引擎
● render_template 函数的第一个参数是模板的文件名,后面的参数都是键值对,表示模板中变量对应的真实值。

{% if user %}
        <title> hello {{user}} </title>
{% else %}
     <title> welcome to flask </title>        
{% endif %}
#--------------------------------
<ul>
    {% for index in indexs %}
    <li> {{ index }} </li>
    {% endfor %}
</ul>
#--------------------------------
#变量
<p>{{mydict['key']}}</p>
<p>{{mylist[1]}}</p>
<p>{{mylist[myvariable]}}</p>
#过滤器
#字符串操作
<p>{{ '<em>hello</em>' | safe }}</p>#禁用转义;
<p>{{ 'hello' | capitalize }}</p>#把变量值的首字母转成大写,其余字母转小写;
<p>{{ 'HELLO' | lower }}</p>#值转成小写
<p>{{ 'hello' | upper }}</p>#值转成大写
<p>{{ 'hello' | title }}</p>#值中的每个单词的首字母都转成大写
<p>{{ ' hello world ' | trim }}</p>#值的首尾空格去掉
<p>{{ 'olleh' | reverse }}</p>#字符串反转
<p>{{ '%s is %d' | format('name',17) }}</p>#格式化输出
<p>{{ '<em>hello</em>' | striptags }}</p>#渲染之前把值中所有的HTML标签都删掉
#列表操作
<p>{{ [1,2,3,4,5,6] | first }}</p>
<p>{{ [1,2,3,4,5,6] | last }}</p>
<p>{{ [1,2,3,4,5,6] | length }}</p>
<p>{{ [1,2,3,4,5,6] | sum }}</p>
<p>{{ [6,2,3,1,5,4] | sort }}</p>
#自定义路由过滤器
#实现方式一:通过调用应用程序实例的add_template_filter方法实现自定义过滤器。该方法第一个参数是函数名,第二个参数是自定义的过滤器名称。
def filter_double_sort(ls):
    return ls[::2]
app.add_template_filter(filter_double_sort,'double_2')
#实现方式二:用装饰器来实现自定义过滤器。装饰器传入的参数是自定义的过滤器名称。
@app.template_filter('db3')
def filter_double_sort(ls):
    return ls[::-3]

#url_for 方法:
{{ request.url }}
{{ config.SQLALCHEMY_DATABASE_URI }}
{{ url_for('index') }}#函数名+参数
{{ url_for('login', id=1) }}
#get_flashed_messages方法:#返回之前在Flask中通过 flash() 传入的信息列表。
{% for message in get_flashed_messages() %}
    {{ message }}
{% endfor %}

2.宏、继承、包含

宏、继承、包含:
宏(Macro)、继承(Block)、包含(include)均能实现代码的复用。

  • 继承(Block)的本质是代码替换,一般用来实现多个页面中重复不变的区域。

  • 宏(Macro)的功能类似函数,可以传入参数,需要定义、调用

  • 包含(include)是直接将目标模板文件整个渲染出来

  • 1.,类似于python中的函数,宏的作用就是在模板中重复利用代码,避免代码冗余。

#定义带参数的宏
{% macro input(name,value='',type='text',size=20) %}
    <input type="{{ type }}"
           name="{{ name }}"
           value="{{ value }}"
           size="{{ size }}"/>
{% endmacro %}
#调用宏,并传递参数
{{ input(value='name',type='password',size=40)}}
#把宏单独抽取出来,封装成html文件,其它模板中导入使用
#macro.html
{% macro function() %}
    <input type="text" name="username" placeholde="Username">
    <input type="password" name="password" placeholde="Password">
    <input type="submit">
{% endmacro %}
#其它模板文件中先导入,再调用
{% import 'macro.html' as func %}
{% func.function() %}
  • 2.模板继承,模板继承是为了重用模板中的公共内容。
#父模板:base.html
{% block top %}
    顶部菜单
  {% endblock top %}
  {% block content %}
  {% endblock content %}
  {% block bottom %}
    底部
  {% endblock bottom %}
#子模板
{% extends 'base.html' %}
{% block content %}
 需要填充的内容
{% endblock content %}
  • 3.包含(Include),它的功能是将另一个模板整个加载到当前模板中,并直接渲染。
{\% include 'hello.html' ignore missing %}

3.请求和响应Request

  • request常用的属性
属性 说明
data 记录请求的数据
form 记录请求中的表单数据
args 记录请求中的查询参数
cookies 请求中的cookie字典对象
headers 记录请求中的报文头
method 记录请求使用的HTTP方法
url 记录请求的URL地址
from flask import Flask
from flask import request
from flask import render_template
from flask import redirect
from flask import make_response


app = Flask(__name__)

@app.route('/login.html', methods=['GET', "POST"])
def login():
    # obj = request.files['the_file_name']
    # obj.save('/var/www/uploads/' + secure_filename(f.filename))

    # 响应相关信息
    # return "字符串"
    # return render_template('html模板路径',**{})
    # return redirect('/index.html')

    # response = make_response(render_template('index.html'))
    # response是flask.wrappers.Response类型
    # response.delete_cookie('key')
    # response.set_cookie('key', 'value')
    # response.headers['X-Something'] = 'A value'
    # return response

    return "内容"

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

三、特殊模块

1.cookie和session(会话)

cookie

#设置cookie
@app.route('/cookie')
def set_cookie():
    resp = make_response('内容')
    resp.set_cookie('username', 'zy',max_age=3600)
    return resp

#获取cookie
@app.route('/request')
def resp_cookie():
    resp = request.cookies.get('username')# 返回的是一个字典,可以获取字典里的相应的值
    return resp

# 删除cookie
@app.route('/request')
def delete_cookie():
    resp = make_response('删除成功')# 返回的是一个字典,可以获取字典里的相应的值
    resp.delete_cookie('username')
    return resp

session(会话)

#Session对象也是一个字典对象,包含会话变量和关联值的键值对。
session['username'] = 'xxx'#设置:
session.pop('username', None)#删除

2.上下文:相当于一个容器,保存了Flask程序运行过程中的一些信息。

Flask中有两种上下文,请求上下文和应用上下文。

请求上下文(request context)
request和session都属于请求上下文对象。
● request:封装了HTTP请求的内容,针对的是http请求。举例:user = request.args.get('user'),获取的是get请求的参数。
● session:用来记录请求会话中的信息,针对的是用户信息。举例:session['name'] = user.id,可以记录用户信息。还可以通过session.get('name')获取用户信息。

3.请求钩子

请求钩子是通过装饰器的形式实现,Flask支持如下四种请求钩子:
● before_first_request:在处理第一个请求前运行。
● before_request:在每次请求前运行。
● after_request:如果没有未处理的异常抛出,在每次请求后运行。
● teardown_request:在每次请求后运行,即使有未处理的异常抛出。

4.Flask-Script扩展命令行

比如我们可以通过python hello.py runserver --host ip地址,告诉服务器在哪个网络接口监听来自客户端的连接。默认情况下,服务器只监听来自服务器所在计算机发起的连接,即localhost连接。
我们可以通过python hello.py runserver --help来查看参数。

from flask import Flask
from flask_script import Manager
app = Flask(__name__)
manager = Manager(app)
@app.route('/')
def index():
    return '床前明月光'
if __name__ == "__main__":
    manager.run()

5.WTForms

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

  • WTForms支持的HTML标准字段
字段对象 说明
StringField 文本字段
TextAreaField 多行文本字段
PasswordField 密码文本字段
HiddenField 隐藏文本字段
DateField 文本字段,值为datetime.date格式
DateTimeField 文本字段,值为datetime.datetime格式
IntegerField 文本字段,值为整数
DecimalField 文本字段,值为decimal.Decimal
FloatField 文本字段,值为浮点数
BooleanField 复选框,值为True和False
RadioField 一组单选框
SelectField 下拉列表
SelectMultipleFeld 下拉列表,可选择多个值
FileField 文本上传字段
SubmitField 表单提交按钮
FormField 把表单作为字段嵌入另一个表单
FieldList 一组指定类型的字段
  • WTForms常用验证函数
验证函数 说明
DataRequired 确保字段中有数据
EqualTo 比较两个字段的值,常用于比较两次密码输入
Length 验证输入的字符串长度
NumberRange 验证输入的值在数字范围内
URL 验证URL
AnyOf 验证输入值在可选列表中
NoneOf 验证输入值不在可选列表中
from flask import Flask,render_template,redirect,url_for,session,request,flash
from flask_wtf import FlaskForm
from wtforms import SubmitField, StringField, PasswordField, Form
from wtforms.validators import DataRequired,EqualTo

app = Flask(__name__)
app.config['SECRET_KEY']='silents'
#自定义表单类,文本字段、密码字段、提交按钮
class Login(FlaskForm):
    us = StringField(label=u'用户:',validators=[DataRequired()])
    ps = PasswordField(label=u'密码',validators=[DataRequired(),EqualTo('ps2','err')])
    ps2 = PasswordField(label=u'确认密码',validators=[DataRequired()])
    submit = SubmitField(u'提交')
@app.route('/login')
def login():
    # return render_template('login.html',form=form)
    return redirect(url_for('index'))
#定义根路由视图函数,生成表单对象,获取表单数据,进行表单数据验证
@app.route('/',methods=['GET','POST'])
def index():
    form = Login()
    if form.validate_on_submit():
        name = form.us.data
        pswd = form.ps.data
        pswd2 = form.ps2.data
        print (name,pswd,pswd2)
        return redirect(url_for('login'))
    else:
        if request.method=='POST':
            flash(u'信息有误,请重新输入!')
        print (form.validate_on_submit())
    return render_template('login.html',form=form)
if __name__ == '__main__':
    app.run(debug=True)

<form method="post">
        #设置csrf_token
        {{ form.csrf_token() }}
        {{ form.us.label }}
        <p>{{ form.us }}</p>
        {{ form.ps.label }}
        <p>{{ form.ps }}</p>
        {{ form.ps2.label }}
        <p>{{ form.ps2 }}</p>
        <p>{{ form.submit() }}</p>
        {% for x in get_flashed_messages() %}
            {{ x }}
        {% endfor %}
 </form>

四、例子

1.登录

from flask import Flask, session, redirect, url_for, escape, request

app = Flask(__name__)


@app.route('/')
def index():
    if 'username' in session:
        return 'Logged in as %s' % escape(session['username'])
    return 'You are not logged in'


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect(url_for('index'))
    return '''
        <form action="" method="post">
            <p><input type=text name=username>
            <p><input type=submit value=Login>
        </form>
    '''


@app.route('/logout')
def logout():
    # remove the username from the session if it's there
    session.pop('username', None)
    return redirect(url_for('index'))


# set the secret key.  keep this really secret:
app.secret_key = 'aaaa'

2.FBV与CBV

#FBV
from flask import Flask,views
app = Flask(__name__)
def wrapper(func):
    def inner(*args,**kwargs):
        print('beforeFunc')
        ret = func(*args,**kwargs)
        return ret
    return inner
# FBV
@app.route('/index1',methods=['GET','POST'])
@wrapper
def index1():
    return "index1"

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

#CBV
#在CBV中,路由信息只能通过add_url_rule()方法添加
from flask import Flask, views


app = Flask(__name__)
class Login(views.MethodView):
    methods = ['POST', 'GET']
    # 如果需要在CBV中加装饰器的话,括号里就是装饰器的内存地址,可以传多个
    decorators = ()
    def get(self):
        print('get 请求')
        return 'login get'
    def post(self):
        print('post 请求')
        return 'login post'
    
app.add_url_rule('/login', view_func=Login.as_view(name='login'))
if __name__ == "__main__":
    app.run(debug=True)

3.restful

flask-restful扩展通过api.add_resource()方法来添加路由,方法的第一个参数是一个类名,该类继承Resource基类,其成员方法定义了不同的HTTP请求方法的逻辑;第二个参数定义了URL路径。在Users类中,我们分别实现了get、post、delete方法,分别对应HTTP的GET、POST、DELETE请求。
另外,flask-restful还提供了argparse,它可以方便地实现对http请求中客户端发送过来的数据进行校验处理,这有点像表单中的验证方法,在实际项目中非常实用。
程序启动以后,我们访问 http://127.0.0.1:5001/users,GET请求时会给出USERS的内容、POST请求时会在USERS中添加一项(如果不存在)并返回USERS更新后的内容。DELETE请求则清空USERS并返回空。

from flask import Flask, jsonify
from flask_restful import Api, Resource, reqparse
USERS = [
    {"name": "zhangsan"},
    {"name": "lisi"},
    {"name": "wangwu"},
    {"name": "zhaoliu"}
]
class Users(Resource):
    # def get(self):
    #     return jsonify(USERS)
    def get(self, userid):
        return jsonify(
            {"name": USERS[int(userid)].get("name")}
        )
    def post(self):
        args = reqparse.RequestParser() \
            .add_argument('name', type=str, location='json', required=True, help="名字不能为空") \
            .parse_args()
        if args['name'] not in USERS:
            USERS.append({"name": args['name']})
        return jsonify(USERS)
    def delete(self):
        USERS = []
        return jsonify(USERS)
app = Flask(__name__)
api = Api(app, default_mediatype="application/json")
api.add_resource(Users, '/users')
app.run(host='0.0.0.0', port=5001, use_reloader=True)

4.登录2

from flask import Flask, request, render_template

app = Flask(__name__)  # Flask类接收一个参数__name__

app.config['SECRET_KEY'] = 'silents is gold'
@app.route('/')  # 装饰器的作用是将路由映射到视图函数index
def hello_world():
    return 'Hello World'


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        print(username, password)
    return render_template('login.html', method=request.method)


if __name__ == '__main__':  # Flask应用程序实例的run方法启动WEB服务器
    app.run(debug=True)


<form method='post'>
    <input type="text" name="username" placeholder='Username'>
    <input type="password" name="password" placeholder='password'>
    <input type="submit">
</form>

总结

不言而喻,重中之重!!

posted @ 2022-01-15 09:59  cactus9  阅读(24)  评论(0编辑  收藏  举报