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>

总结

不言而喻,重中之重!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

joyyi9

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

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

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

打赏作者

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

抵扣说明:

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

余额充值