目录:
一、变量引用
内容:
备注:PyCharm小技巧,comm+alt+l 自动修改格式,comm+alt+return 向上添加新行
一、变量引用
1、url生成
from flask import Flask,render_template #在Flask中使用render_template代替render使用 app = Flask('__name__') @app.route('/') #所有的url都使用app.route做装饰器来引用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{{ url_for('static',filename='style.css') }}"/>
</head>
<body>
<h1>{{ title }}</h1>
<a href="{{ url_for('.services') }}">Services</a>
<a href="{{ url_for('.about') }}">About</a>
</body>
</html>
def hello_world(): return render_template('index.html', title='Hello World') @app.route('/services') def services(): return 'Services!' if __name__ == '__main__': app.run()
2、增加debug
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return '<h1>Hello World!</h1>' if __name__ == '__main__': app.run(debug=True) #增加这个参数,可以在修改完毕后不重启直接运行
3、配置文件
在根目录下使用一个config.py文件,内容:
DEBUG = True
在主配置文件中,添加:
import config
app = Flask(__name__)
在这添加config内容:
app.config.from_object(config) #通过这种方式添加配置文件
备注:
SECRET_KEY和SQLCHAMY均可以放在config.py文件中使用
二、路由
1、普通路由,带字符串式
@app.route('/user/<username>') def user(username): return 'User %s' % username
2、带数字
分类:
1、int
2、float
3、path
@app.route('/user1/<int:user_id>') def user1(user_id): return 'User_id %s' % user_id
3、正则表达式方式URL
from flask import Flask, render_template from werkzeug.routing import BaseConverter class RegexConverter(BaseConverter): def __init__(self,url_map,*items): super(RegexConverter,self).__init__(url_map) self.regex = items[0] app = Flask(__name__) app.url_map.converters['regex'] = RegexConverter @app.route('/user2/<regex("[a-z]{3}"):user2_id>') def user2(user2_id): return 'user2 %s' % user2_id
4、url的类型:
在app.route中的关键字定义有两种:
- @app.route('/about') 文件名类型,后面不能加‘/’ 这个类似于文件名
- @app.route('/projects/') 文件夹类型,后面还可以跟文件名
URL反转:
from flask import Flask,url_for
@app.route('/')
def index():
print(url_for('my_list')) #通过url_for方式可以将my_list对应的URL打印出来,这种方式通常用于template的文件中,用这种方式映射,在修改了url后,由于url_for对应的是函数名称,所以不受影响,仍然可以映射到正确的视图函数
print(url_for('article',id='abc'))
return 'Hello World'
@app.roue('/list')
def my_list():
return 'list'
@app.route('/article/<id>/')
def article(id):
return '你请求的id是%s' %id
反转URL:
1、什么叫反转URL:从视图函数到url的转换叫反转url
2、反转url用处:
在页面重定向时候,会使用url反转
在模板中,也会使用url反转
5、Flask中一个views函数对应多个URL
@app.route('/projects/') @app.route('/program/') def projects(): return 'The Projects Page'
6、POST与GET方法
@app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] print(username, password) return redirect(url_for('index')) # else: # username = request.args['username'] return render_template('login.html', method=request.method)
7、上传文件
@app.route('/uploads', methods=['GET', 'POST']) def uploads(): if request.method == 'POST': f = request.files['file'] print(f.filename) basepath = path.abspath(path.dirname(__file__)) upload_path = path.join(basepath, 'static/uploads') f.save(path.join(upload_path, secure_filename(f.filename))) return redirect(url_for('uploads')) return render_template('upload.html')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/uploads" method="POST" enctype="multipart/form-data"> <input type="file" name="file"/> <input type="submit" value="提交"/> </form> </body> </html>
8、cookie
@app.route('/projects/') @app.route('/program/') def projects(): request.cookies['username'] #获取cookie return 'The Projects Page'
from flask import Flask, render_template, request, redirect, url_for, make_response from werkzeug.routing import BaseConverter from os import path from werkzeug.utils import secure_filename @app.route('/') def hello_world(): response = make_response(render_template('index.html', title='welcome ')) response.set_cookie('username','a') #设置cookie return response
9、自定义错误代码页面
app.route('/users/<user_id>') def users(user_id): if int(user_id) == 1: return render_template("user.html") else: abort(404) #定义异常代码以便被异常方法捕获
@app.errorhandler(404) def page_not_found(error): return render_template('404.html'), 404
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>404</h1> <h1>很抱歉!</h1> <p>访问的页面不存在</p> </body> </html>
10、消息捕获:
后端通过flash方法发送提示,前端通过get_flashed_messages()[0]方法来获取提示
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>{{ get_flashed_messages()[0] }}</h1> //由于消息只有一条消息,所以消息提示的数组使用第一条记录 </body> </html>
from flask import Flask, flash, render_template app = Flask(__name__) app.secret_key = '123' #当消息提示时会使用秘钥进行加密 @app.route('/') def hello_world(): flash('hello user') return render_template('index.html')
二、包管理
通过pip命令生成一个requirements文件
. venv/bin/active
pip freeze > requirements.txt 生成一个文件
如果要安装的话:
pip install -r requirements.txt
安装包:
Flask_Script
from flask import Flask, render_template, request, redirect, url_for, make_response, abort from werkzeug.routing import BaseConverter from os import path from werkzeug.utils import secure_filename from flask_script import Manager # from flask.ext.script import Manager class RegexConverter(BaseConverter): def __init__(self, url_map, *items): super(RegexConverter, self).__init__(url_map) self.regex = items[0] app = Flask(__name__) # UPLOAD_FOLDER = 'static/uploads/' # app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER app.url_map.converters['regex'] = RegexConverter manager = Manager(app) @app.route('/user2/<regex("[a-z]{3}"):user2_id>') def user2(user2_id): return 'user2 %s' % user2_id @app.route('/') def index(): # abort(404) response = make_response(render_template('index.html', title='welcome ')) response.set_cookie('username','a') #设置cookie return response @app.errorhandler(404) def page_not_found(error): return render_template('404.html'), 404 @app.route('/services') def services(): return 'Services' @app.route('/user/<username>') def user(username): return 'User %s' % username @app.route('/user1/<int:user_id>') def user1(user_id): return 'User_id %s' % user_id @app.route('/about') def about(): return 'About' @app.route('/projects/') @app.route('/program/') def projects(): request.cookies['username'] #获取cookie return 'The Projects Page' @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] print(username, password) return redirect(url_for('index')) # else: # username = request.args['username'] return render_template('login.html', method=request.method) @app.route('/uploads', methods=['GET', 'POST']) def uploads(): if request.method == 'POST': f = request.files['file'] print(f.filename) basepath = path.abspath(path.dirname(__file__)) upload_path = path.join(basepath, 'static/uploads') f.save(path.join(upload_path, secure_filename(f.filename))) return redirect(url_for('uploads')) return render_template('upload.html') if __name__ == '__main__': # app.run(debug=True) manager.run()
通过终端运行python3 learn_flask.py runserver
三、jinjia2模板
首先创建flask项目后 ,需要写两个文件夹,static和template
在template目录里写一个index.html文件:
<body>
<p>用户名:{{ username }}</p>
<p>年龄:{{ age }}</p>
<p>性别:{{ gender }}</p>
</body>
在视图函数里添加:
from flask import Flask,render_template
@app.route('/')
def index():
contex ={
'username': 'gavin',
'age': '18',
''gender:'male',
}
return render_template('index.html',**context) #如果有多个参数需要传递,可以使用字典的方式进行传参
在模板中如果要使用一般变量,语法{{变量名}}
访问模型中的属性或者字典,可以通过‘{{ params.property }}’的形式,或者是使用{{ params['age'] }}的形式
例子:
index.html中:
<p>{{ person.name }}</p>
<p>{{ person.age }}</p>
<p>{{ websites.baidu }}</p>
<p>{{ websites.google }}</p>
视图函数中:
from flask import Flask,render_template
@app.route('/')
def index():
class Person(object):
name = 'gavin'
age = 18
p = Person()
contex ={
'username': 'gavin',
'age': '18',
''gender:'male',
'person': p,
'websites':{
'baidu': 'www.baidu.com',
'google': 'www.google.com.hk',
},
}
return render_template('index.html',**context)
备注:
在jinjia2中可以针对传递的变量的索引进行操作:
例子:
1、 {% if loop.index is odd %}| {% endif %} 如果索引为奇数,加 |
2、{% if not loop.first %} |{% endif %} 如果不是第一个索引,加 |
2、if判断:
index.html中:
{% if user and user.age > 18 %}
{{内容}}
{% else %}
{{内容}}
{% endif %}
3、for循环
字典的遍历:可以使用items()/keys()/values()/iteritems()/iterkeys()/itervalues()
index.html中:
{% for k,v in user.items() %}
<p>{{k}}: {{v}}</p>
{% endfor%}
列表的遍历:
{% for a in list1 %}
{{a}}
{% endfor %}
4、过滤器
介绍:可以处理变量,原始的变量经过处理后展示出来,作用的对象的变量
语法:
{{ avater|default(‘xxx’)}} 如果当前变量不存在,可以指定默认值
<p>评论数 {{ comments|length }}</p> 求列表、字符串、字典、元组的长度
5、继承
作用:可以把一些公共的代码放在base模板中
语法:
{% extends ‘base.html’%}
{%block XXX%}
{% endblock %}
block实现:
作用:可以让子模板实现一些自己的需求,父模板必须定义好
子模板中的代码,必须放在block块中
四、URL链接和静态文件
url链接:使用url_for(‘视图函数名称’),可以反正url
加载静态文件:
1、语法:‘url_for('static',filename='路径')’
2、静态文件,flask会从static文件夹汇总开始寻找,所以不需要再写static这个路径了
3、可以加载css文件、js文件、iamge文件
例子:
首先static目录下建立css目录,在css目录下建立index.css文件
然后在index.html中添加<link rel='stylesheet' href="{{ url_for('static',filename="css/index.css") }}">
五、SQLAlchemy:
配置文件:
config.py:
DIALECT = 'mysql'
DRIVER = 'mysqldb'
USRNAME = 'root'
PASSWORD = 'root'
HOST = '127.0.0.1'
PORT = '3306'
DATABASE = 'db_demo1'
SQLALCHEMY_DATABASE_URI = "{}+{}://{}:{}@{}:{}/{}?charset=utf8".format(DIALECT,DRIVER,USRNAME,PASSWORD,HOST,PORT,DATABASE)
SQLALCHEMY_TRACK_MODIFICATIONS = True
视图函数:
from flask_sqlalchemy import SQLAlchemy
import config
app = Flask(__name__)
app.config.from_object(config)
db = SQLALchemy(app)
#article表
class Article(db.Model):
__tablename__ = 'article'
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
title = db.Column(db.String(100),nullable=False)
content = db.Column(db.Text,nullable=False)
db.create_all()#创建表
对数据库进行增删改查操作:
视图函数中:
@app.route('/')
def index():
#增加
article = Article(title='a',content='b')
db.session.add(article)
#事务操作(必须有commit才进行操作,上面操作还没有进行事务操作)
db.session.commit()#完成事务操作后才真正写入数据库中
#查
@app.route('/')
def index():
result = Article.query.filter(Article.title=='a').all() #query是专门用于查找的,query是从db.Model中继承下来的,这里返回的是Query对象,如果想只取第一个对象,可以使用first()代替all()
print(result[0].title,result[0].content)
#改
1、先把要改的数据查找出来
2、对该数据进行更改
3、做事务提交
article = Article.query.filter(Article.title='a').first()
article.title = 'new title'
db.session.commit()
#删
article = Article.query.filter(Article.title='a').first()
db.session.delete(article)
db.session.commit()
外键约束:
语法:
author_id = db.Column(db.Integer,db.ForeignKey('user.id'))
author = db.relationship('User',backref=db.backref('articles'))#这个模型添加一个author属性,可以访问这篇文章的作者的数据,像访问普通模型一样
backref是定义反向引用,可以通过User.articles这个模型访问这个模型所写的所有文章
例子:
首先创建了两个表
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
username = db.Column(db.String(100),nullable=False)
class Article(db.Model):
__tablename__ = 'article'
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
title = db.Column(db.String(100),nullable=False)
content = db.Column(db.Text,nullable=False)
author_id = db.Column(db.Integer,db.ForeignKey('user.id'))
author = db.relationship('User',backref=db.backref('articles')) #第一个参数是管理到那个模型的名字
db.create_all()
#添加文章与用户
@app.route('/')
def index():
user1 = User(username='gavin')
db.session.add(user1)
article = Article(title='a',content='b')
article.author = User.query.filter(id==1).first() #在添加作者时通过author方式进行添加
db.session.add(aricle)
db.session.commit()
#需求:要找标题为a的文章的作者
article = Article.query.filter(Article.title=='a').first()
print(article.author.username) #通过title查找作者
#需求:找到作者写过的所有文章
author = User.query.filtr(User.username=='gavin').first()
result = author.articles
for article in result:
print(print.article.title)
多对多:
article_tag = db.Table('article_tag'
db.Column('article_id',db.Integer,db.ForeignKey('article_id'),primary_key=True),
db.Column('tag_id', db.Integer.db.ForeighKey('tag_id'),primary_key=True),
)
class Article(db.Model):
__tablename__ = 'article'
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
title = db.Column(db.String(100),nullable=False)
tags = db.relationship('Tag', secondary=article_tag,backhref=db.backhref('articles'))
class Tag(db.Model):
__tablename__ = 'tag'
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
name = db.Column(db.String(100),nullable=False)
db.create_all()
@app.route('/')
def index():
article1 = Article(title='aaa')
article2 = Article(title='bbb')
tag1 = Tag(name='111')
tag2 = Tag(name='222')
article1.tags.append(tag1)
article1.tags.append(tag2)
article2.tags.append(tag1)
article.2tags.append(tag2)
db.session.add_all(article1,article2,tag1,tag2)
db.session.commit()
article1 = Article.query.filter(Article.title=='aaa').first()
tags = article1.tags
for tag in tags:
print(tag.name)
备注:
如果要求前端显示按照顺序进行,可以添加:order_by(),在括号内需要添加models里对应数据库函数对应的条目,例如order_by('create_time')
就是按照创建时间来排序,按照正序方式进行,如果想倒序,只需要order_by('-create_time')方式来进行
六、flask-script
作用:通过命令行的形式操作flask,例如通过命令跑一个并发版本的服务器,设置数据库,定时任务等,要使用flask-scrtipt,可以通过pip install flask-script安装最新版本,首先看一个简单的例子:
创建一个manager.py文件:
from flask_script import Manager
from your_app import app
manager = Manager(app)
@manager.command
def hello():
print('hello')
if __name__ == '__main__':
manager.run()
可以在script中完成数据库操作:
1、创建一个db_scrtipt.py文件
from flask_script import Manager
DBmanager = Manger()
@DBmanager.command
def init():
print('数据库初始化完成')
@DBmanager.command
def migrate():
print('数据表迁移完成')
回到manage.py文件中添加:
from flask_script import Manager
from your_app import app
from db_script import DBmanager
manager = Manager(app)
@manager.command
def hello():
print('hello')
manager.add_command('db',DBmanager) #db表示想要操作DBmanager的话使用的一个标示,可以是任意,后面DBmanger表示引用
if __name__ == '__main__':
manager.run()
执行操作:
python3 manage.py db init #完成初始化操作
python3 manage.py db migrate #完成迁移操作
定义命令的三种方法:
1、使用@command装饰器
2、使用类继承自Command类:
七、分开models和解决循环引用
1、分开models的目的,是为了代码简洁
2、解决循环引用的方法,把db放在另外一个文件中,切断循环引用
八、flask_migrate
例子:
1、创建exts.py文件:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
2、创建models.py文件
from exts import db
def Article(db.Model):
__tablename__ = 'article'
id = db.Column(db.Integer,primary_key= True,autocrement=True)
title = db.Column(db.String(100),nullable=False)
3、config.py文件
DIALECT = 'mysql'
DRIVER = 'mysqldb'
USRNAME = 'root'
PASSWORD = 'root'
HOST = '127.0.0.1'
PORT = '3306'
DATABASE = 'db_demo1'
SQLALCHEMY_DATABASE_URI = "{}+{}://{}:{}@{}:{}/{}?charset=utf8".format(DIALECT,DRIVER,USRNAME,PASSWORD,HOST,PORT,DATABASE)
SQLALCHEMY_TRACK_MODIFICATIONS = True
4、视图函数
from flask import Flask
from exts import db
from models import Article
import config
app = Flask(__name__)
app.config.from_object(config)
db.init_app(app) #由于exts没有指定哪个数据库,所以需要在这里重新指定
with app.app_context():
db.create_all()
如果此时要添加数据库的结构,需要进行migrate
1、介绍:因为采用db.create_all()在后期修改字段的时候,不会字段的映射到数据库中,必须删除表,然后重新运行,这样不符合我的要求,因此flask-migrate就是为了解决这种歌问题,它可以在每次修改模型后,可以将修改的东西映射到数据库中
2、首先进入到虚拟机环境中,然后使用pip install flask_migrate进行安装
使用:
1、flask-script方式
首先创建manage.py文件 :
from flask_script import Manager
from <视图函数名字> import app
from flask_migrate import Migrate,MigrateCommand
from models import Article #需要导入这个,migrate才知道要对哪个表进行迁移
from exts import db
manager = Manager(app)
#1、要使用flask_migrate,必须绑定db和app
migrate = Migrate(app,db)
#2、把MigrateCommand命令加到manager中
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
其次回到视图函数中,将
with app.app_context():
db.create_all()
条目删除
最后执行:#模型-->迁移文件 --> 表
python manage.py db init #生成migrate文件夹
python manage.py db migrate #将模型生成迁移文件
python manage.py db upgrade #将迁移文件生成表
九、cookie和session
1、cookie:出现原因:在网站里,http请求是无状态的,也就是说即使第一次和服务器连接后并且登录成功,第二次请求服务器依然不知道当前请求是哪个用户,cookie的出现就是为了解决这个问题,第一次登录服务器返回一个数据cookie给浏览器,然后浏览器保存再本地,当该用户第二次请求时,就会自动把上次请求存储的cookie数据字典携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个
2、如果服务器返回了cookie给浏览器,那么浏览器下次再请求相同的服务器时,会自动把cookie发送给服务器,这个过程中,用户不需要管
3、cookie是保存在浏览器中,相对的的是浏览器
session:
1、session介绍:session和cookie的作用类似都是为了保存用户相关形象,不同的是cookie是存储在浏览器,而session是存储在服务器,存在服务器的数据更加安全,不容易被窃取,但存储在服务器也有一定的弊端,就是会占用服务器资源,但是现在服务器发展到今天,这些session新潮存储绰绰有余
2、使用session的好处:
敏感数据不是直接发送给浏览器,而是发送回一个session_id 服务器将session_id和敏感数据做一个映射存储在session(服务器上面)中,更加安全
session可以设置过期时间,也从另外一个方面,保存了用户的账号安全
flask中session工作机制:
flask中的session机制:把敏感数据加密后放入session中,再把session存放在cookie中,下次请求的时候,再从浏览器发送过来的cookie中读取session,在从session中读取敏感数据,并进行解密,获取最终数据
flask的这种session机制,可以节省服务器开销,因为把所有的信息都存在到了客户端(浏览器)
安全是相对的,吧session放到cookie中也是经过加密的
例子:
视图函数:
from flask import Flask,session
app = Flask(__name__)
#添加数据到session中
#操作session的时候,和操作字典是一样的
#SECRET_KEY 放在config.py文件中,或者直接单独设置
import os
#app.config[SECRET_KEY] = '必须24个字符的字符串'
app.config['SECRET_KEY'] = os.urandom(24)
#如果不想超时时间为31天(默认)可以按照如下设置
from datetime import timedelta
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
@app.route('/')
def hello_world():
#如果没有指定session过期时间,那么在浏览器结束就过期
session['username'] = 'gavin'
#如果设置session.permanent=True,默认情况下(没有设置app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(XX))session的超时时间为31天
session.permanent = True
return 'hellow world'
@app.route('/get/')
def get():
#获取session,如果不存在会返回None
return session.get('username')
@app.route('/delete')
def delete():
print(session.get('username'))
#删除session
session.pop('username')
print session.get('username')
return 'success'
@app.route('/clear/')
def clear():
print(session.get('username'))
#删除session中的所有数据
session.clear()
print session.get('username')
return 'success'
if __name__ == '__main__':
app.run(debug=True)
十、get与post请求
1、get请求:
使用场景:如果只对服务器获取数据不对服务器产生影响,使用get请求
传参: get请求传参是放在url中并且是通过?的形式来指定key和value的
2、post请求:
使用场景:如果要对服务器产生影响,使用post请求
传参:post请求传参是通过form data的形式发送给服务器
例子:
from flask import Flask,render_tempalte,request
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/search/')
def search():
#arguments,以字典的形式获取url中所有参数
print(request.args) #get请求可以通过request.args来获取数据,post请求可以通过request.form.get来获取数据
return 'success'
#默认的视图函数只能采用get请求,如果要采用post请求,要单独说明
@app.route('/login/',method=['GET','POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
return 'login'
在index.html中:
<a href="{{ urlf_for('search',q="hello")}}">跳转到搜索</a>
在login.html中:
<form action='{{ url_for('login')}}' method='post'>
<input type='text' name="username"/>
<input type='password' name='password'/>
<inpu ttype='submit' />
</form>
十一、g变量
g变量就是global的简称,可以使用:
from flask import g的方式调用,
在g变量中可以使用类似于jinjia2的方式赋值,g.username = ‘gavin’ 、g.password=123
在g变量引入后,在整个项目的其他文件想引用,可以直接从from flask import g后直接引用,无序通过传参方式赋值,但是g只在每一次请求时生效,等下一次请求时g会被第二次赋值,就不是原来的数据了
十二、钩子函数
1、before_request 在任何请求之前执行,在执行完毕后再执行视图函数中其他函数,这个代码只是一个装饰器,它可以把需要设置为钩子函数的代码放到视图函数执行之前来执行
例子:
视图函数:
from flask import Flask,render_template,request,session,redirect,url_for,g
import os
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)
@app.route('/')
def index():
return render_to_template('index.html')
@app.route('/login',methods=['GET','POST'])
def login():
if request.method == 'post':
username = request.form.get('username')
password = request.form.get('password')
if username == 'gavin' and password == '123':
session['username'] == username
return 'success'
else:
return 'fail to login'
return render_template('login.html')
@app.route('/edit/')
def edit():
if hasattr(g,'username'):
return '修改成功'
else:
return direct(url_for('login'))
@app.before_request
def my_before_request():
user_id = session.get('user_id')
user = User.query.filter(User.id == user_id).first()
if session.get('username'):
g.username = session.get('username')
if __name__ == '__main__':
app.run(debug=True)
在login.html中:
<form action='{{ url_for('login')}}' method='post'>
<input type='text' name="username"/>
<input type='password' name='password'/>
<inpu ttype='submit' />
</form>
2、context_processor
上下文处理器应该返回一个字典,字典中的key会被模板中当做变量来渲染
上下文处理器中返回的字典,在所有页面都是可用的
被这个装饰器修饰的钩子函数,必须返回一个字典,即使是空的字典
例子:
from flask import Flask,render_template,request,session,redirect,url_for,g
import os
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)
@app.route('/')
def index():
return render_to_template('index.html')#有了context_processor以后,不需要在这里传递参数,template里的html文件照样可以接收模板文件
@app.route('/login',methods=['GET','POST'])
def login():
if request.method == 'post':
username = request.form.get('username')
password = request.form.get('password')
if username == 'gavin' and password == '123':
session['username'] == username
return 'success'
else:
return 'fail to login'
return render_template('login.html')
@app.route('/edit/')
def edit():
if hasattr(g,'username'):
return '修改成功'
else:
return direct(url_for('login'))
@app.before_request
def my_before_request():
user_id = session.get('user_id')
user = User.query.filter(User.id == user_id).first()
if session.get('username'):
g.username = session.get('username',)
@app.context_processor
def my_context_processor():
username = session.get('username')
if username:
return {'username': username} #返回了这个字典,在所有模板里都会把这个当做模板去渲染
if __name__ == '__main__':
app.run(debug=True)
十二、livereload方法
livereload方法可以实现自动加载任意修改的界面
from flask import Flask, render_template from livereload import Server app = Flask(__name__) @app.route('/') def index(): return render_template('index.html', title="<h1>Hello World!</h1>") if __name__ == '__main__': #导入app.wsgi服务 live_server = Server(app.wsgi_app) #watch用来监控哪个界面,这种方式表示所有页面 live_server.watch('**/*.*') #开启livereload服务 live_server.serve(open_url_delay=True)
十三、表单
备注:
首先表单提交需要避免跨站请求攻击CSRF
创建一个config.py文件
import os DEBUG = True SECRET_KEY = os.urandom(24)
创建forms.py文件,里面填写表单内容
from flask_wtf import Form from wtforms import StringField, PasswordField, SubmitField from wtforms.validators import DataRequired class LoginForm(Form): #DataRequired()要求这个字段必须有值 username = StringField(label="用户名", validators=[DataRequired()]) password = PasswordField(label="密码", validators=[DataRequired()]) submit = SubmitField(label="提交")
主配置文件中引入该forms.py文件
from flask import Flask, render_template from livereload import Server from flask_bootstrap import Bootstrap import config app = Flask(__name__) app.config.from_object(config) bootstrap = Bootstrap(app) @app.route('/login/',methods=['GET','POSt']) def login(): from forms import LoginForm form = LoginForm() return render_template('login.html',title="登录",form=form)
在login.html文件中添加
{% extends "bootstrap/base.html" %} {% block content %} <div class="container"> <form action="{{ url_for('login') }}" method="POSt"> {{ form.username.label }} {{ form.username() }} {{ form.password.label }} {{ form.password() }} {{form.submit() }} </form> </div> {% endblock %}
wtf表单样式与校验器样式:
校验器样式:
十四、消息提示和异常处理
消息提示:
在登录页面,如果有步骤错误,比如没输入用户名或密码,都会有消息提示,在flask中使用flash()方式进行消息提示,这个提示在前端html中,使用{{get_flashed_messages()}}方式来获取
from flask import Flask, flash, render_template, request app = Flask(__name__) #flask在使用消息提示时,会使用secret_key进行加密 app.secret_key = '123' @app.route('/') def hello_world(): flash('Hello Gavin') return render_template('index.html') @app.route('/login',methods=['get','post']) def login(): username = request.form.get('username') password = request.form.get('password') if not username: flash("请输入用户名") return render_template('index.html') if not password: flash('请输入密码') return render_template('index.html') elif username == 'gavin' and password == '123': flash('登录成功') return render_template('index.html') else: flash('用户名或密码错误') return render_template('index.html') if __name__ == '__main__': app.run()
异常处理:
在页面找不到时,需要做异常处理,返回自己特色的页面,而不是使用flask提供的原生页面
@app.route('/users/<user_id>') def users(user_id): if int(user_id) == 1: return render_template('user.html',user_id=user_id) else: #如果条件不满足,置为状态码,然后送入到异常处理界面处理 abort(404) #使用errorhandler来处理404异常,如果捕获到异常就按照下面的函数进行处理 @app.errorhandler(404) def not_found(error): return render_template('404.html')