什么是Flask框架?

Flask是一个使用 Python 编写的轻量级 Web 应用框架。

导入Flask类;
from flask import Flask
#实例化一个Flask对象,
#     __name__是模块的名称或者包的名称
#     作用: 根据这个参数确定flask应用的路径, 从而快速查找模板和html文件的默认路径;
#     模块就是python文件; 包就是目录(跟普通目录多加一个__init__.py);
app = Flask(__name__)
#基本路由:通过路由绑定一个视图函数
#   @app.route('/'): 告诉Flask哪个URL才能出发对应的函数, 又称为路由;
#   对应定义了一个视图函数, 也就是返回给用户浏览器显示的内容;
@app.route('/')
def index():return '<h1>hello world</h1>'
@app.route('/login/')
def login():return 'login'
#  运行Flask应用, 可以指定ip和端口;
# '0.0.0.0' 所有的IP都可以访问到;
app.run('0.0.0.0',9000)

路由与变量规则

常见路由的规则

  1. url的一部分可以标记为变量<变量名>
  2. flask中路由里面的变量常见类型:
    int, string, float, path, uuid
from flask import Flask,request
app = Flask(__name__)
@app.route('/<int:id>/coomments/')
def comment1(id):return 'Comment id:%s' %(id)
@app.route('/welcome/<string:user>/')
def welcome(user):return user+'用户欢迎您!'
# 特殊的url地址: http://www.baidu.com/query?id=123&name=cooffee
@app.route('/query')
def query():id = request.args.get('id')name = request.args.get('name')return 'id:%s,name:%s' %(id,name)
app.run()



url构建反向URL

from flask import Flask,request,url_for
app = Flask(__name__)
@app.route('/welcome/<string:user>/')
def welcome(user):return user + "用户欢迎您"
@app.route('/path/')
def path():print(request.headers)# 查看默认url地址的请求方法;# methods is a list of methods this rule should be limited# to (``GET``, ``POST`` etc.).  By default a rule# just listens for ``GET``print(request.method)# url_for: 根据函数名, 反向生成url地址print("用户正在访问url地址:%s" %(url_for(endpoint='welcome',user='cooffee')))return "用户正在访问url地址:%s" %(url_for(endpoint='welcome',user='cooffee'))
app.run(port=9001)

常见http方法之post与get

1.常见HTTP请求方法:
GET: 1). 获取信息 2). 提交的信息会展示在url: http://www.floating.org/login?user=cooffee&passwd=cooffee
POST:1). 提交信息, 不在url里面展示, 有利于数据的安全性;
2.默认路由接受的请求方法为get
3.如何指定接收多个HTTP请求方法app.route(’/login/’, methods=[‘GET’, ‘POST’])
4.如何判断用户请求的HTTP方法request.method
5.如何获取用户POST请求提交的表单数据request.form[‘user’]
6.模板渲染(jinja2):
why? python中生成html不易修改与维护, 所以将html的内容独立到templates目录中;
how?
1). 去当前项目目录下寻找templtes是否存在?再去判断templates目录下是否有login.html文件?
2). 读取这个login.html文件的内容, 作为render_template的返回值;
3). 最终返回给用户浏览器;
render_template(‘login.html’)
7.重定向和错误?
redirect(url_for(‘index’))
return render_template(‘login.html’, message=“用户名或者密码错误”)
注意:这需要在工程下建立static文件夹来保存css,font,img,js
建立templates文件夹来保存html页面
而run.py为主程序

from flask import Flask,request,render_template,redirect,url_for,abort
app = Flask(__name__)
@app.route('/')
def index():return render_template('index.html')
@app.route('/login/',methods=['GET','POST'])
def login():if request.method == 'POST':print(request.form)# 1. 如何获取到用户提交的信息呢?user = request.form['user']passwd = request.form['passwd']# 2. 判断用户名和密码是否正确if user == 'root' and passwd == 'cooffee':# 如果登陆成功, 跳转到主页;return redirect(url_for('index'))else:# 如果登陆失败, 重新登陆;return render_template('login.html',message='用户名或者密码错误')else:# 用户是GET请求, 返回登陆的html页面# 1. 读取login.html文件的内容# 2. 将读取的内容返回给用户界面return render_template('login.html')
# 404异常处理: 类似于捕获异常
@app.errorhandler(404)
def not_found(e):return render_template('404.html')
# 抛出异常
@app.route('/user/<int:user_id>/')
def user(user_id):if 0<int(user_id)<=100:return "欢迎访问:%s" %(user_id)else:abort(404)
app.run(port=9002)

什么是jinjia2模板引擎?

python的Web开发中, 业务逻辑(实质就是视图函数的内容)和页面逻辑(html
文件)分开的, 使得代码的可读性增强, 代码容易理解和维护;
模板渲染: 在html文件中,通过动态赋值 , 将重新翻译好的html文件(模板引擎生效) 返回给用户的过程。
其他的模板引擎: Mako, Template, Jinja2

jianja2的常用用法

变量显示

Jinja2变量显示语法: {{ 变量名 }}
for循环:
{% for i in li%}
{% endfor %}

if语句
{% if user == ‘root’%}
{% elif user == ‘hello’ %}
{% else %}
{% endif%}

from flask import Flask,render_template
app = Flask(__name__)
class User(object):def __init__(self,name,passwd):self.name = nameself.passwd = passwddef __str__(self):return "<User:%s>" %(self.name)@app.route('/')
def index1():name = "this is a message"li = [1,2,4,5]d = dict(a=1,b=2)u = User("cooffee",'passwd')return render_template('index1.html',name=name,li = li,d= d,u= u)
app.run(port=9003)

html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<p>变量:</p>{{name}}
<p>列表:</p>{{li}}
{% for i in li %}
<br>列表元素显示:{{i}}
{% endfor %}
<p>字典:</p> {{d}}
<p>字典:</p> {{d.a}}
<p>字典:</p> {{d['b']}}
<p>对象:</p>{{u}}
<table><tr><th>用户名</th><td>密码</td></tr><tr><td>{{u.name}}</td><td>{{u.passwd}}</td></tr>
</table>
</body>
</html>

过滤器与自定义过滤器

什么是过滤器?
实质上就是一个转换函数/方法

import time
from flask import Flask,render_template
app = Flask(__name__)
class User(object):def __init__(self,name,passwd):self.name =nameself.passwd = passwddef __str__(self):return "<User:%s>" %(self.name)
@app.route('/')
def index2():name = 'this is a message'li = [1,2,4,5]d = dict(a=1,b=2)lidict = [{'count':100,'price':30},{'count':110,'price':20}]u = User('cooffee','passwd')timestamp = time.time()return render_template('index2.html',name=name,li=li,d = d,u = u,lidict = lidict,timestamp = timestamp)
def format_data(value,format="%Y-%m-%d %H:%M:%S"):ttime = time.localtime(value)return time.strftime("%Y-%m-%d %H:%M:%S",ttime)#添加过滤器(函数名,过路器名)
app.add_template_filter(format_data,'format_date')@app.route('/index3')
def index3():return render_template('index3.html',timestamp=time.time())
app.run(port=9004)

index2.html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
{{ timestamp }}
{{ timestamp | format_date }}
/*常见的字符串过滤器操作:*/
<ul><li>{{ name | upper }}</li><li>{{ name | lower }}</li><li>{{ "hello" | capitalize }}</li><li>{{ " hello world" | capitalize }}</li><li>{{ name | reverse }}</li>
</ul>
/*常见数值操作*/
<ul><!--四舍五入--><li>{{ -12.9623423435 | round }}</li><li>{{ -12.9623423435 | round | abs }}</li></ul>
/*列表常见:*/
<ul><li>{{li}}</li><li>{{li|first}}</li><li>{{li|last}}</li><li>{{li|length}}</li><li>{{li|sum}}</li><li>{{li|sort|reverse}}</li><li>{{li|join(":")}}</li><li>{{["hello","world"]|upper}}</li><li>{{["hello","woRld"]|lower}}</li>
</ul>
/*列表包含字典常用操作:*/
<ul>{% for item in lidict | sort(attribute='price',reverse=false) %}{{item}}{% endfor %}
</ul>
</body>
</html>


index3.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
{{timestamp}}
#使用刚才自定义的fotmat_date过滤器
{{timestamp | format_date}}
</body>
</html>

模板的继承
模板继承语法:1. 如何继承某个模板?{% extends "模板名称" %}2. 如何挖坑和填坑?挖坑:{% block 名称 %}默认值{% endblock %}填坑:{% block 名称 %}{% endblock %}3. 如何调用/继承被替代的模板?挖坑:{% block 名称 %}默认值{% endblock %}填坑:{% block 名称 %}#如何继承挖坑时的默认值?{{ super() }}# 后面写新加的方法.........{% endblock %}

base.html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>{% block title %}首页{% endblock %} | cooffee</title><link rel="stylesheet" href="../static/css/bootstrap.min.css"><link rel="stylesheet" href="../static/css/main.css"><script src="../static/js/bootstrap.min.js"></script>
</head>
<body><!--导航栏-->
<nav class="navbar navbar-default"><div class="container-fluid"><!-- Brand and toggle get grouped for better mobile display --><div class="navbar-header"><button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a class="navbar-brand" href="index.html"></a></div><!-- Collect the nav links, forms, and other content for toggling --><div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"><ul class="nav navbar-nav"><li class="active" style="padding-bottom: 15px;"><a href="index.html">首页<span class="sr-only">(current)</span></a></li><li><a href="#">国内</a></li><li><a href="#">数读</a></li><li><a href="#">社会</a></li></ul><ul class="nav navbar-nav navbar-right"><li><a href="/login/">登陆</a></li><li><a href="signup.html">注册</a></li></ul></div><!-- /.navbar-collapse --></div><!-- /.container-fluid -->
</nav>
{% block content %}{% endblock %}
<div class="footer">京ICP备11008151号京公网安备11010802014853</div></body>
</html>

index.html:

{% extends "base.html" %}{% block title %}
{# <!--继承挖坑时填的默认值--> #}
{{super()}}{% endblock %}{% block content %}
<div class="container container-fluid"><div class="row"><!--左侧导航--><div class="col-xs-2"><div class="list-group left-side"><a class="list-group-item left-side-active" href="#">综合</a><a class="list-group-item" href="#">电影</a><a class="list-group-item" href="#">电视剧</a><a class="list-group-item" href="#"> 明星</a><a class="list-group-item" href="#">娱乐</a></div></div><!--中间新闻--><div class="col-xs-7"><div class="media"><div class="media-left"><a href="news.html"><img class="media-object news-png"src="../static/img/index1.jpg"alt="新闻图片"></a></div><div class="media-body"><h4 class="media-heading"><b>2年前他为教育和高圆圆分手,今成这般,高圆圆:我有一句MMP如哽在喉</b></h4><div class="news-info"><img class="news-logo" src="../static/img/u=1271327272,62771227&fm=26&gp=0.jpg"><span>王花花</span>.<span>25K评论</span>.<span>7分钟前</span></div></div></div><div class="media"><div class="media-left"><a href="news.html"><img class="media-object news-png"src="../static/img/2.2.jpg"alt="新闻图片"></a></div><div class="media-body"><h4 class="media-heading"><b>2年前他为教育和高圆圆分手,今成这般,高圆圆:我有一句MMP如哽在喉</b></h4><div class="news-info"><img class="news-logo" src="../static/img/u=1271327272,62771227&fm=26&gp=0.jpg"><span>王花花</span>.<span>25K评论</span>.<span>7分钟前</span></div></div></div><div class="media"><div class="media-left"><a href="news.html"><img class="media-object news-png"src="../static/img/2.jpg"alt="新闻图片"></a></div><div class="media-body"><h4 class="media-heading"><b>2年前他为教育和高圆圆分手,今成这般,高圆圆:我有一句MMP如哽在喉</b></h4><div class="news-info"><img class="news-logo" src="../static/img/u=1271327272,62771227&fm=26&gp=0.jpg"><span>王花花</span>.<span>25K评论</span>.<span>7分钟前</span></div></div></div><div class="media"><div class="media-left"><a href="news.html"><img class="media-object news-png"src="../static/img/2.2.jpg"alt="新闻图片"></a></div><div class="media-body"><h4 class="media-heading"><b>2年前他为教育和高圆圆分手,今成这般,高圆圆:我有一句MMP如哽在喉</b></h4><div class="news-info"><img class="news-logo" src="../static/img/u=1271327272,62771227&fm=26&gp=0.jpg"><span>王花花</span>.<span>25K评论</span>.<span>7分钟前</span></div></div></div><div class="media"><div class="media-left"><a href="news.html"><img class="media-object news-png"src="../static/img/index1.jpg"alt="新闻图片"></a></div><div class="media-body"><h4 class="media-heading"><b>2年前他为教育和高圆圆分手,今成这般,高圆圆:我有一句MMP如哽在喉</b></h4><div class="news-info"><img class="news-logo" src="../static/img/u=1271327272,62771227&fm=26&gp=0.jpg"><span>王花花</span>.<span>25K评论</span>.<span>7分钟前</span></div></div></div><div class="media"><div class="media-left"><a href="news.html"><img class="media-object news-png"src="../static/img/2.2.jpg"alt="新闻图片"></a></div><div class="media-body"><h4 class="media-heading"><b>2年前他为教育和高圆圆分手,今成这般,高圆圆:我有一句MMP如哽在喉</b></h4><div class="news-info"><img class="news-logo" src="../static/img/u=1271327272,62771227&fm=26&gp=0.jpg"><span>王花花</span>.<span>25K评论</span>.<span>7分钟前</span></div></div></div><!--页角--><nav aria-label="Page navigation"><ul class="pagination"><li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">上一页</span></a></li><li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li><li><a href="#">2 <span class="sr-only">(current)</span></a></li><li><a href="#">3 <span class="sr-only">(current)</span></a></li><li><a href="#">4 <span class="sr-only">(current)</span></a></li><li><a href="#">... <span class="sr-only">(current)</span></a></li><li><a href="#">10 <span class="sr-only">(current)</span></a></li><li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">下一页</span></a></li></ul></nav></div><div class="col-xs-3"><!--搜索栏--><div class="input-group input-info"><input type="text" class="form-control" placeholder="搜一下"></div><!--有害信息--><div class="bad-infomation"><table id="bad-table"><tr><td rowspan="2"><img class="bad-jpg" src="../static/img/4.png"></td><td id="bad-font1">有害信息举报专区</td></tr><tr><td id="bad-font2">举报电话12377</td></tr></table></div><!--新闻推荐--><div class="list-group hot-news"><a href="#" class="list-group-item"><span style="font-size: larger"><b>24小时热闻</b></span></a><a href="#" class="list-group-item"><span style="font-size: large"> Lorem ipsum dolor sit amet,consectetur adipisicing</span><div class="news-info"><span>25K评论</span><span>7分钟前</span></div></a><a href="#" class="list-group-item"><span style="font-size: large"> Lorem ipsum dolor sit amet,consectetur adipisicing</span><div class="news-info"><span>25K评论</span><span>7分钟前</span></div></a><a href="#" class="list-group-item"><span style="font-size: large"> Lorem ipsum dolor sit amet,consectetur adipisicing</span><div class="news-info"><span>25K评论</span><span>7分钟前</span></div></a><a href="#" class="list-group-item"><span style="font-size: large"> Lorem ipsum dolor sit amet,consectetur adipisicing</span><div class="news-info"><span>25K评论</span><span>7分钟前</span></div></a><a href="#" class="list-group-item"><span style="font-size: large"> Lorem ipsum dolor sit amet,consectetur adipisicing</span><div class="news-info"><span>25K评论</span><span>7分钟前</span></div></a></div></div></div>
</div>
{% endblock %}

run.py:

from flask import Flask,request,render_template,redirect,url_for,abort
app = Flask(__name__)
@app.route('/')
def index():return render_template('index.html')
@app.route('/login/',methods=['GET','POST'])
def login():if request.method == 'POST':print(request.form)user = request.form['user']passwd = request.form['passwd']if user == 'root' and passwd == 'cooffee':return redirect(url_for('index'))else:return render_template('login.html',message='用户名或者密码错误')else:return render_template('login.html')
@app.errorhandler(404)
def not_found(e):return render_template('404.html')
@app.route('/user/<int:user_id>/')
def user(user_id):if 0<int(user_id)<=100:return "欢迎访问:%s" %(user_id)else:abort(404)
app.run(port=9002)

宏macro的使用

macro.html:
宏: 是一个函数

{% macro input(type,name,text) %}<div class="form-group"><label>{{text}}</label><input name={{name}} type={{type}} class="form-control username-text"></div>
{% endmacro %}

login.html:

{% extends "base.html" %}{% block title %}
登陆
{% endblock %}
{% block content %}<!--登陆界面--><div class="container container-small login"><h1>登录<small>没有账号?<a href="signup.html">注册</a></small></h1><form action="/login/" method="post"><!--<div class="form-group">--><!--<label>用户名/手机/邮箱</label>--><!--<input name="user" type="text" class="form-control username-text">--><!--</div>--><!--<div class="form-group">--><!--<label>密码</label>--><!--<input name="passwd" type="password" class="form-control username-text">--><!--</div>-->{% import 'macro.html' as macro %}{{macro.input('text','user','用户名/手机/邮箱')}}{{macro.input('password','passwd','密码')}}<div class="form-group"><button class="btn btn-primary btn-block block-sure" type="submit">登录</button></div><div class="form-group"><a href="#">忘记密码?</a></div>{% if message %}<p style="color: red">{{message}}</p>{% endif %}</form></div>
{% endblock %}

session操作

cookie: 客户端浏览器的缓存;
session: 服务端服务器的缓存;

Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,
存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的
Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,
服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。

from flask import Flask,session
import random
app = Flask(__name__)
# 设置是24位的字符, 每次运行服务器的secret_key都是不同的,
# 服务器重启后会清除上一次存储的session信息值;
app.config['SECRET_KEY'] =random._urandom(24)
# 设置session值;
@app.route("/")
def index():session['name']='cooffee'return  "hello world"
# 如何获取?
@app.route('/get/')
def get():return session.get('name')# 如何删除?
@app.route('/delete/')
def delete():print(session.get('name'))session.pop('name')print(session.get('name'))return 'delete'
app.run(port=9006)



判断用户是否登陆的装饰器
import  functoolsdef is_login(f):@functools.wraps(f)def wrapper(*args, **kwargs):# run函数代码里面, 如果登陆, session加入user, passwd两个key值;# run函数代码里面, 如果注销, session删除user, passwd两个key值;# 如果没有登陆成功, 则跳转到登陆界面if 'user' not in session:return  redirect('/login/')# 如果用户是登陆状态, 则访问哪个路由, 就执行哪个路由对应的视图函数;return  f(*args, **kwargs)return  wrapper

run.py:

import random
import functools
from flask import Flask, request, render_template, redirect, url_for, abort, sessionapp = Flask(__name__)
app.config['SECRET_KEY'] = random._urandom(24)
def is_login(f):@functools.wraps(f)def wrapper(*args,**kwargs):if 'user' not in session:return redirect(url_for('login'))return f(*args,**kwargs)return wrapper#先判断是否登陆,若登陆才能进入到主页
@app.route('/')
@is_login
def index():return render_template('index.html')@app.route('/login/',methods=['GET','POST'])
def login():if request.method == 'POST':print(request.form)user = request.form['user']passwd = request.form['passwd']if user == 'root' and passwd == 'cooffee':# 将用户名和密码信息存储到session中;session['user']=usersession['passwd']=passwd# 如果登陆成功, 跳转到主页;return redirect(url_for('index'))else:# 如果登陆失败, 重新登陆;return render_template('login.html',message='用户名或者密码错误')else:# 用户是GET请求, 返回登陆的html页面# 1. 读取login.html文件的内容# 2. 将读取的内容返回给用户界面return render_template('login.html')
@app.errorhandler(404)
def not_found(e):return render_template('404.html')
@app.route('/user/<int:user_id>/')
def user(user_id):if 0<int(user_id)<=100:return "欢迎访问:%s" %(user_id)else:abort(404)
app.run(port=9002)
上传文件

实现目标: 如何将文件上传到服务器(保存在指定的文件夹)

import os
from flask import Flask,request,render_template
app = Flask(__name__)
@app.route('/upload/',methods=['GET','POST'])
def upload():if request.method == 'POST':# 获取到用户上传的文件对象f = request.files['faceImg']# 获取当前项目所在目录位置;basepath = os.path.dirname(__file__)# 拼接路径, 存储文件到static/face/xxxxfiename = os.path.join(basepath,'static/face',f.filename)# 保存文件f.save(fiename)return render_template('upload.html',message="上传成功")else:return render_template('upload.html')
app.run(port=9007)

upload.html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form action="/upload/" method="post" enctype="multipart/form-data"><input type="file" name="faceImg"><input type="submit" value="提交">{%  if message %}<p style="color: red">{{ message }}</p>{% endif %}</form>
</body>
</html>


表单处理flask-wtf
  1. 为什么使用Flask-WTF?
    request对象公开了所有客户端发送的请求信息。特别是request.form可以访问POST请求提交的表单数据。
    尽管Flask的request对象提供的支持足以处理web表单,但依然有许多任务会变得单调且重复。
    表单的HTML代码生成和验证提交的表单数据就是两个很好的例子。
    优势:
    Flask-WTF扩展使得处理web表单能获得更愉快的体验。该扩展是一个封装了与框架无关的WTForms包的Flask集成。

  2. 什么是表单处理?

    在网页中,为了和用户进行信息交互总是不得不出现一些表单。
    flask设计了WTForm表单库来使flask可以更加简便地管理操作表单数据。
    WTForm中最重要的几个概念如下:

    1). Form类,开发者自定义的表单必须继承自Form类或者其子类。
    Form类最主要的功能是通过其所包含的Field类提供对表单内数据的快捷访问方式。

    2). 各种Field类,即字段。一般而言每个Field类都对应一个input的HTML标签。
    比如WTForm自带的一些Field类比如BooleanField就对应,
    SubmitField就对应等等。

    3). Validator类。这个类用于验证用户输入的数据的合法性。
    比如Length验证器可以用于验证输入数据的长度,
    FileAllowed验证上传文件的类型等等。

    另外,flask为了防范csfr(cross-site request forgery)攻击,
    默认在使用flask-wtf之前要求app一定要设置过secret_key。
    最简单地可以通过app.config[‘SECRET_KEY’] = 'xxxx’来配置。

  3. 常见的Field类

    PasswordField   密码字段,自动将输入转化为小黑点

    DateField   文本字段,格式要求为datetime.date一样

    IntergerField   文本字段,格式要求是整数

    DecimalField   文本字段,格式要求和decimal.Decimal一样

    FloatField   文本字段,值是浮点数

    BooleanField   复选框,值为True或者False

    RadioField   一组单选框

    SelectField   下拉列表,需要注意一下的是choices参数确定了下拉选项,
    但是和HTML中的 标签一样,其是一个tuple组成的列表,
    可以认为每个tuple的第一项是选项的真正的值,而第二项是alias。

    MultipleSelectField  可选多个值的下拉列表

  4. Validator是验证函数: 
    Validator是验证函数,把一个字段绑定某个验证函数之后,flask会在接收表单中的数据之前对数据做一个验证,
    如果验证成功才会接收数据。验证函数Validator如下,具体的validator可能需要的参数不太一样,这里只给出
    一些常用的,更多详细的用法可以参见wtforms/validators.py文件的源码,参看每一个validator类需要哪些参数:

    *基本上每一个validator都有message参数,指出当输入数据不符合validator要求时显示什么信息。

    Email  验证电子邮件地址的合法性,要求正则模式是.+@([.@][^@]+)$

    EqualTo  比较两个字段的值,通常用于输入两次密码等场景,可写参数fieldname,不过注意其是一个字符串变量,指向同表单中的另一个字段的字段名

    IPAddress  验证IPv4地址,参数默认ipv4=True,ipv6=False。如果想要验证ipv6可以设置这两个参数反过来。

    Length  验证输入的字符串的长度,可以有min,max两个参数指出要设置的长度下限和上限,注意参数类型是字符串,不是INT!!

    NumberRange  验证输入数字是否在范围内,可以有min和max两个参数指出数字上限下限,注意参数类型是字符串,不是INT!!然后在这个validator的message参数里可以设置%(min)s和%(max)s两个格式化部分,来告诉前端这个范围到底是多少。其他validator也有这种类似的小技巧,可以参看源码。

    Optional  无输入值时跳过同字段的其他验证函数

    Required  必填字段

    Regexp  用正则表达式验证值,参数regex=‘正则模式’

    URL  验证URL,要求正则模式是[a-z]+://(?P<host>[/:]+)(?P:[0-9]+)?(?P /.*)?$

    AnyOf  确保值在可选值列表中。参数是values(一个可选值的列表)。特别提下,和SelectField进行配合使用时,不知道为什么SelectField的choices中项的值不能是数字。。否则AnyOf的values参数中即使有相关数字也无法识别出当前选项是合法选项。我怀疑NoneOf可能也是一样的套路。

    NoneOf  确保值不在可选值列表中
    forms.py:

from flask_wtf import FlaskForm
from flask_wtf.file import FileRequired, FileAllowed
from wtforms import StringField, PasswordField, SubmitField, FileField
from wtforms.validators import DataRequired, Lengthclass LoginForm(FlaskForm):name = StringField(label="用户名/邮箱/手机号",validators=[DataRequired(message=u"请输入用户名"),Length(3, 10, message=u"长度不符"),])passwd = PasswordField(label="密码",validators=[DataRequired(message=u"输入密码"),Length(3, 10,message=u"长度不符")] )file = FileField(label="简历",validators=[FileRequired(),FileAllowed(['pdf', 'txt'], 'pdf 能被接收')])

run.py:

import random
from flask import Flask, redirect, render_template, flash
from _Flask框架.forms import LoginForm
from flask_bootstrap import  Bootstrap
app = Flask(__name__)
bootstrap = Bootstrap(app)
app.config['SECRET_KEY'] =  random._urandom(24)
@app.route('/success/')
def success():return  "success"@app.route('/login/', methods=('GET', 'POST'))
def submit():# 实例化表单对象;form = LoginForm()if form.validate_on_submit():print(form.data)flash(form.name.data+'|'+form.passwd.data)return redirect('/success/')return render_template('wtflogin.html', form=form)
app.run(port=8000)

wtflogin.html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form method="POST" action="/login/">{{form.hidden_tag()}}<p>{{ form.name.label }} {{ form.name }}{%for e in form.name.errors%}<span style="color: red">{{e}}</span>{% endfor %}</p><p>{{ form.passwd.label }} {{ form.passwd }}{%for j in form.name.errors%}<span style="color: red">{{j}}</span>{%endfor%}</p><p>{{ form.file }}</p><input type="submit" value="Go">
</form>
</body>
</html>

用flask框架及jinja2引擎优化new项目

目录结构

templates

base.html:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>{% block title %}首页{% endblock %} | cooffee</title><link rel="stylesheet" href="../static/css/bootstrap.min.css"><link rel="stylesheet" href="../static/css/main.css"><script src="../static/js/bootstrap.min.js"></script>
</head>
<body><!--导航栏-->
<nav class="navbar navbar-default"><div class="container-fluid"><!-- Brand and toggle get grouped for better mobile display --><div class="navbar-header"><button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a class="navbar-brand" href="index.html"></a></div><!-- Collect the nav links, forms, and other content for toggling --><div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"><ul class="nav navbar-nav"><li class="active" style="padding-bottom: 15px;"><a href="index.html">首页<span class="sr-only">(current)</span></a></li><li><a href="#">国内</a></li><li><a href="#">数读</a></li><li><a href="#">社会</a></li><li><a href="/sysinfo/">系统信息</a></li><li><a href="#">登陆用户</a></li></ul><ul class="nav navbar-nav navbar-right">{% if 'user' in session %}<!--<li><a><span class="glyphicon glyphicon-user"></span></a></li>--><li><a href="#">{{session.user}}</a></li><li><a href="/logout/">注销</a></li>{% else %}<li><a href="/login/">登陆</a></li><li><a href="/register/">注册</a></li>{% endif %}</ul></div><!-- /.navbar-collapse --></div><!-- /.container-fluid -->
</nav>
{% block content %}{% endblock %}
<div class="footer">京ICP备11008151号京公网安备11010802014853</div></body>
</html>
index.html:
{% extends "base.html" %}{% block title %}{{super()}}{% endblock %}{% block content %}
<div class="container container-fluid"><div class="row"><!--左侧导航--><div class="col-xs-2"><div class="list-group left-side"><a class="list-group-item left-side-active" href="#">综合</a><a class="list-group-item" href="#">电影</a><a class="list-group-item" href="#">电视剧</a><a class="list-group-item" href="#"> 明星</a><a class="list-group-item" href="#">娱乐</a></div></div><!--中间新闻--><div class="col-xs-7"><div class="media"><div class="media-left"><a href="news.html"><img class="media-object news-png"src="../static/img/index1.jpg"alt="新闻图片"></a></div><div class="media-body"><h4 class="media-heading"><b>2年前他为教育和高圆圆分手,今成这般,高圆圆:我有一句MMP如哽在喉</b></h4><div class="news-info"><img class="news-logo" src="../static/img/u=1271327272,62771227&fm=26&gp=0.jpg"><span>王花花</span>.<span>25K评论</span>.<span>7分钟前</span></div></div></div><div class="media"><div class="media-left"><a href="news.html"><img class="media-object news-png"src="../static/img/2.2.jpg"alt="新闻图片"></a></div><div class="media-body"><h4 class="media-heading"><b>2年前他为教育和高圆圆分手,今成这般,高圆圆:我有一句MMP如哽在喉</b></h4><div class="news-info"><img class="news-logo" src="../static/img/u=1271327272,62771227&fm=26&gp=0.jpg"><span>王花花</span>.<span>25K评论</span>.<span>7分钟前</span></div></div></div><div class="media"><div class="media-left"><a href="news.html"><img class="media-object news-png"src="../static/img/2.jpg"alt="新闻图片"></a></div><div class="media-body"><h4 class="media-heading"><b>2年前他为教育和高圆圆分手,今成这般,高圆圆:我有一句MMP如哽在喉</b></h4><div class="news-info"><img class="news-logo" src="../static/img/u=1271327272,62771227&fm=26&gp=0.jpg"><span>王花花</span>.<span>25K评论</span>.<span>7分钟前</span></div></div></div><div class="media"><div class="media-left"><a href="news.html"><img class="media-object news-png"src="../static/img/2.2.jpg"alt="新闻图片"></a></div><div class="media-body"><h4 class="media-heading"><b>2年前他为教育和高圆圆分手,今成这般,高圆圆:我有一句MMP如哽在喉</b></h4><div class="news-info"><img class="news-logo" src="../static/img/u=1271327272,62771227&fm=26&gp=0.jpg"><span>王花花</span>.<span>25K评论</span>.<span>7分钟前</span></div></div></div><div class="media"><div class="media-left"><a href="news.html"><img class="media-object news-png"src="../static/img/index1.jpg"alt="新闻图片"></a></div><div class="media-body"><h4 class="media-heading"><b>2年前他为教育和高圆圆分手,今成这般,高圆圆:我有一句MMP如哽在喉</b></h4><div class="news-info"><img class="news-logo" src="../static/img/u=1271327272,62771227&fm=26&gp=0.jpg"><span>王花花</span>.<span>25K评论</span>.<span>7分钟前</span></div></div></div><div class="media"><div class="media-left"><a href="news.html"><img class="media-object news-png"src="../static/img/2.2.jpg"alt="新闻图片"></a></div><div class="media-body"><h4 class="media-heading"><b>2年前他为教育和高圆圆分手,今成这般,高圆圆:我有一句MMP如哽在喉</b></h4><div class="news-info"><img class="news-logo" src="../static/img/u=1271327272,62771227&fm=26&gp=0.jpg"><span>王花花</span>.<span>25K评论</span>.<span>7分钟前</span></div></div></div><!--页角--><nav aria-label="Page navigation"><ul class="pagination"><li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">上一页</span></a></li><li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li><li><a href="#">2 <span class="sr-only">(current)</span></a></li><li><a href="#">3 <span class="sr-only">(current)</span></a></li><li><a href="#">4 <span class="sr-only">(current)</span></a></li><li><a href="#">... <span class="sr-only">(current)</span></a></li><li><a href="#">10 <span class="sr-only">(current)</span></a></li><li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">下一页</span></a></li></ul></nav></div><div class="col-xs-3"><!--搜索栏--><div class="input-group input-info"><input type="text" class="form-control" placeholder="搜一下"></div><!--有害信息--><div class="bad-infomation"><table id="bad-table"><tr><td rowspan="2"><img class="bad-jpg" src="../static/img/4.png"></td><td id="bad-font1">有害信息举报专区</td></tr><tr><td id="bad-font2">举报电话12377</td></tr></table></div><!--新闻推荐--><div class="list-group hot-news"><a href="#" class="list-group-item"><span style="font-size: larger"><b>24小时热闻</b></span></a><a href="#" class="list-group-item"><span style="font-size: large"> Lorem ipsum dolor sit amet,consectetur adipisicing</span><div class="news-info"><span>25K评论</span><span>7分钟前</span></div></a><a href="#" class="list-group-item"><span style="font-size: large"> Lorem ipsum dolor sit amet,consectetur adipisicing</span><div class="news-info"><span>25K评论</span><span>7分钟前</span></div></a><a href="#" class="list-group-item"><span style="font-size: large"> Lorem ipsum dolor sit amet,consectetur adipisicing</span><div class="news-info"><span>25K评论</span><span>7分钟前</span></div></a><a href="#" class="list-group-item"><span style="font-size: large"> Lorem ipsum dolor sit amet,consectetur adipisicing</span><div class="news-info"><span>25K评论</span><span>7分钟前</span></div></a><a href="#" class="list-group-item"><span style="font-size: large"> Lorem ipsum dolor sit amet,consectetur adipisicing</span><div class="news-info"><span>25K评论</span><span>7分钟前</span></div></a></div></div></div>
</div>
{% endblock %}

login.html:
{% extends "base.html" %}{% block title %}
登陆
{% endblock %}
{% block content %}<!--登陆界面--><div class="container container-small login"><h1>登录<small>没有账号?<a href="/register/">注册</a></small></h1><form action="/login/" method="post"><!--<div class="form-group">--><!--<label>用户名/手机/邮箱</label>--><!--<input name="user" type="text" class="form-control username-text">--><!--</div>--><!--<div class="form-group">--><!--<label>密码</label>--><!--<input name="passwd" type="password" class="form-control username-text">--><!--</div>-->{% import 'macro.html' as macro %}{{macro.input('text','user','用户名/手机/邮箱')}}{{macro.input('password','passwd','密码')}}<div class="form-group"><button class="btn btn-primary btn-block block-sure" type="submit">登录</button></div><div class="form-group"><a href="#">忘记密码?</a></div>{% if message %}<p style="color: red">{{message}}</p>{% endif %}</form></div>
{% endblock %}


singnup.html:
{% extends "base.html" %}{% block title %}
注册
{% endblock %}
{% block content %}<!--注册界面-->
<div class="container container-small login"><h1>注册<small>没有账号?<a href="/register/">注册</a></small></h1><form action="/register/" method="post">{% import 'macro.html' as macro %}{{macro.input('text','user','用户名/手机/邮箱')}}{{macro.input('password','passwd','密码')}}<!--<div class="form-group">--><!--<label>手机</label>--><!--<input type="text" class="form-control username-text">--><!--</div>--><!--&lt;!&ndash;<div class="form-group username-text">&ndash;&gt;--><!--&lt;!&ndash;<label>验证码</label>&ndash;&gt;--><!--&lt;!&ndash;&lt;!&ndash;<div class="input-group">&ndash;&gt;&ndash;&gt;--><!--&lt;!&ndash;&lt;!&ndash;<input type="text" class="form-control">&ndash;&gt;&ndash;&gt;--><!--&lt;!&ndash;&lt;!&ndash;<div class="input-group-btn">&ndash;&gt;&ndash;&gt;--><!--&lt;!&ndash;&lt;!&ndash;<div class="btn btn-default">获取验证码</div>&ndash;&gt;&ndash;&gt;--><!--&lt;!&ndash;&lt;!&ndash;</div>&ndash;&gt;&ndash;&gt;--><!--&lt;!&ndash;&lt;!&ndash;</div>&ndash;&gt;&ndash;&gt;--><!--&lt;!&ndash;</div>&ndash;&gt;--><!--<div class="form-group">--><!--<label>密码</label>--><!--<input type="password" class="form-control username-text">--><!--</div>--><div class="form-group"><button class="btn btn-primary btn-block block-sure" type="submit">注册</button></div><div class="form-group">注册咖啡或浮云即代表您同意<a href="#">咖啡或浮云服务条款</a></div>{% if message %}<p style="color: red">{{message}}</p>{% endif %}</form></div>
{% endblock %}

macro.html:
{% macro input(type,name,text) %}<div class="form-group"><label>{{text}}</label><input name={{name}} type={{type}} class="form-control username-text"></div>
{% endmacro %}
sysinfo.html:
{% extends 'base.html' %}{% block title %} 系统信息 {% endblock %}{% block content %}{#    表格内容----bootstrap #}
<table class="table table-striped" style="width: 50%; margin: auto " ><tr><td><b style="font-size: large">系统信息</b></td><td></td></tr><tr><td>主机名</td><td>{{ hostname }}</td></tr><tr><td>内核名称</td><td>{{ sysname }}</td></tr><tr><td>发行版本号</td><td>{{ release }}</td></tr><tr><td>内核版本</td><td>{{ version}}</td></tr><tr><td>系统构架</td><td>{{ machine }}</td></tr><tr><td>现在时间</td><td>{{ now_time }}</td></tr><tr><td>开机时间</td><td>{{ boot_time }}</td></tr><tr><td>运行时间</td><td>{{ delta_time }}</td></tr>
</table>{% endblock %}

404.html:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h2 style="color: red;">404: 页面未找到</h2></body>
</html>

程序

models.py:

连接数据库

import pymysql
conn = pymysql.connect(host='172.25.254.78',user='cooffee',password='cooffee',charset='utf8',db='cooffee')cur = conn.cursor()
def isUserExist(username):sqli = "select * from flaskdata where name='%s'" %(username)res = cur.execute(sqli)if res == 0:return Falseelse:return True
def isPasswdOk(username,passwd):sqli = sqli = "select * from flaskdata where name='%s' and passwd='%s'" %(username, passwd)res = cur.execute(sqli)if res == 0:return Falseelse:return Truedef addUser(username,passwd):sqli = "insert into flaskdata (name, passwd) values('%s', '%s')" %(username, passwd)try:res= cur.execute(sqli)conn.commit()except Exception as e:conn.rollback()return e
if __name__ == "__main__":addUser('root','root')print(isUserExist('root'))print(isPasswdOk('root','root'))

run.py:
import random
import functoolsimport os
from datetime import datetimeimport psutil as psutil
from flask import Flask, request, render_template, redirect, url_for, abort, session
from models import isPasswdOk, isUserExist, addUser
app = Flask(__name__)
app.config['SECRET_KEY'] = random._urandom(24)
def is_login(f):"""判断用户是否登陆的装饰器"""@functools.wraps(f)def wrapper(*args,**kwargs):# run函数代码里面, 如果登陆, session加入user, passwd两个key值;# run函数代码里面, 如果注销, session删除user, passwd两个key值;# 如果没有登陆成功, 则跳转到登陆界面if 'user' not in session:return redirect(url_for('login'))# 如果用户是登陆状态, 则访问哪个路由, 就执行哪个路由对应的视图函数;return f(*args,**kwargs)return wrapper# 用户主页
@app.route('/')
def index():return render_template('index.html')# 用户登陆按钮
@app.route('/login/',methods=['GET','POST'])
def login():if request.method == 'POST':print(request.form)user = request.form['user']passwd = request.form['passwd']if isPasswdOk(user,passwd):# 将用户名和密码信息存储到session中;session['user']=usersession['passwd']=passwdreturn redirect(url_for('index'))else:return render_template('login.html',message='用户名或者密码错误')else:return render_template('login.html')
# 用户注销
@app.route('/logout/')
def logout():session.pop('user',None)session.pop('passwd',None)return redirect(url_for('index'))
# 用户注册
@app.route('/register/',methods=['GET','POST'])
def register():if request.method == 'POST':user = request.form['user']passwd = request.form['passwd']if isUserExist(user):message = "用户已经存在"return render_template('signup.html',message=message)else:addUser(user,passwd)return redirect(url_for('login'))else:return render_template('signup.html')@app.route('/sysinfo/')
@is_login
def sysinfo():info = os.uname()boot_time = psutil.boot_time()boot_time = datetime.fromtimestamp(boot_time)now_time = datetime.now()delta_time = now_time - boot_timedelta_time = str(delta_time).split('.')[0]return render_template('sysinfo.html',hostname=info.nodename,sysname=info.sysname,release=info.release,version= info.version,machine=info.machine,now_time=str(now_time).split('.')[0],boot_time=boot_time,delta_time=delta_time)
# 404异常处理: 类似于捕获异常
@app.errorhandler(404)
def not_found(e):return render_template('404.html')app.run(port=9002)

Flask框架及jinja2引擎模版相关推荐

  1. Flask框架基础Jinja2模板

    Flask框架基础Jinja2模板-- 潘登同学的flask学习笔记 文章目录 Flask框架基础Jinja2模板-- 潘登同学的flask学习笔记 return 模板 Template 模板的使用 ...

  2. Flask 框架下 Jinja2 模板引擎高层 API 类——Environment

    Environment 类版本: 本文所描述的 Environment 类对应于 Jinja2-2.7 版本. Environment 类功能: Environment 是 Jinja2 中的一个核心 ...

  3. Flask框架二 Jinja2

    1.简介: 什么是Jinja2,Jinja2起什么作用 Jinja2是Python下一个被广泛应用的模版引擎,且它自带一个感觉挺nb的转义功能 作用1.它起了让前端和后端分离的作用 2.减少了Flas ...

  4. Flask框架的学习——04—(模版继承、静态文件的配置、豆瓣APP界面案例实现)

    1.模版继承 Flask中的模板可以继承,通过继承可以把模板中许多重复出现的元素抽取出来,放在父模板中,并且父模板通过定义block给子模板开一个口,子模板根据需要,再实现这个block,假设现在有一 ...

  5. Flask框架10(Jinja2模板继承)

    Jinja2模板继承 #!/usr/bin/env python # -*- coding: utf-8 -*- from flask import Flask,render_template &qu ...

  6. flask框架中的Jinja2模板引擎

    简介 在flask框架中通常使用Jinja2模板引擎来实现复杂页面的渲染. 本章主要介绍Jinja2模板引擎的基本结构和使用方法. 如何使用flask框架渲染模板 在模板中传递一个或者多个参数 if语 ...

  7. Flask 中的Jinja2模板引擎

    Flask 中的Jinja2模板引擎 在 Web 项目中,前端的显示效果是通过 HTML 语言来实现的,后端的视图函数将数据或模板文件返回给前端. 前端接收到后端返回的结果后,需要通过模板引擎来渲染页 ...

  8. Flask框架之Jinja 2模板引擎

    文章目录 3.6宏的定义及使用 3.6.1 宏的定义 3.6.2 宏的导入 3.6.3 include的使用 3.7 set和with语句的使用 3.8静态资源文件的加载 3.9模板的继承 3.6宏的 ...

  9. python之flask框架详解

    目录 前言 1.新建文件helloworld.py 2.相关配置参数 3.加载配置文件 3.1配置对象加载 3.2配置文件加载 3.3读取配置 4 路由定义 4.1指定路由地址 4.2 给路由传参 4 ...

最新文章

  1. uniapp 中如何使用echart_uniapp中如何引用echarts
  2. Python语言学习之字母R开头函数使用集锦:random/range/replace/reshape用法之详细攻略
  3. 如何在Windows系统上使用Object Detection API训练自己的数据?
  4. 《MySQL实战45讲》实践篇 24-29 学习笔记 (主备篇)
  5. icd植入是大手术吗_骨折手术植入了钢板,骨折痊愈后,需要取出钢板吗?
  6. 将对话框(提示框)中的内容粘贴到记事本
  7. ghost不要用作域控的备份
  8. 吃的苦中苦,方为人上人!
  9. php修改ip6地址为ip4,CentOS7 设置静态IPv6/IPv4地址
  10. 命令行模式下编译多个C/C++源文件
  11. centos7.6 LNMP新版本
  12. 利用FreeType和OpenGL进行矢量字体渲染
  13. mysql 运算符转义_我的MYSQL学习心得(五) 运算符
  14. HG255D刷flash记录
  15. 【Apple苹果设备刷机】ipad已停用,iTunes无法联系网络等问题
  16. 参数化三维管网建模系统MagicPipe3D
  17. SEO优化与网站浏览量提升
  18. linux远程连接交换机,总结:交换机远程登陆的两种方式,Telnet与SSH那种好?
  19. 位操作的应用实例(2)位掩码
  20. 12.2版本数据库ORA-20001: Statistics Advisor: Invalid task name for the current user

热门文章

  1. 如何画出一个漂亮的思维导图
  2. 油耳不敢戴耳机?分享几款油耳也能戴的无线蓝牙耳机
  3. J2EE开发常用架构及其性能
  4. 180度舵机与360度舵机
  5. python接口自动化基础框架结构 ——分层
  6. 全球十大物流企业的成功经验借鉴
  7. 【论文粗读】Pick-and-Learn: Automatic Quality Evaluationfor Noisy-Labeled Image Segmentation
  8. experiment : 使用WMI取本地计算机信息
  9. Back-off restarting failed container
  10. java实现简易计算器完整代码