1、虚拟环境
1)安装虚拟环境
sudo pip install virtualenv
sudo pip install virtualenvwrapper
2)查看 虚拟环境版本
virtualenv --version
3)配置环境变量
mkdir $HOME/.virtualenvs
vim ~/.bashrc
添加 export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
source ~/.bashrc
4)创建虚拟环境
mkvirtualenv Flask_py
5)进入虚拟环境
workon Flask_py
6)退出虚拟环境
deactivate Flask_py
7)查看当前虚拟环境工具包
pip freeze > requirements.txt
8)根据工具包版本安装工具包
pip install -r requirements.txt
2、demo
from flask import Flask
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST']) //装饰器定义路径和调用方法
def index():
return 'index page'
if __name__ == '__main__':
app.run()
3、print(name) // demo.py
入口文件打印 main
非入口文件打印 demo
4、静态文件设置
app = Flask(name,
static_url_path = '/static', //访问静态资源前缀
static_floder = 'static', //静态资源目录
template_floder = 'templates') //模版目录
5、设置配置信息、current_app(app的同名词)
from flask import Flask, current_app
class Config():
debug = True
lang = python
app.config.from_object(Config)
@app.route('/')
def index():
print(app.config.get('debug')) //True
print(current_app.config.get('debug')) //True
return 'index'
6、同一个路由对应多个试视图函数,执行第一个
7、多个路径对应同一个视图函数,通过添加多个装饰器的方式添加
8、redirect、url_for
from flask
@app.route('/')
def index():
return 'index.html'
@app.route('/login')
def login():
if login:
redirect(url_for('index'))
9、转换器
@app.route(’/send/int:mobile’)
def senfMobile(mobile):
return 'mobile is %d' % mobile
10、自定义转换器、to_python、to_path函数(过滤)
from werkzeug.routing import BaseConverter
//定义转换器类
class RegexConverter(BaseConverter)
def __init__(self, url_map, regex):
super(RegexConverter, self).__init__(url_map)
self.regex = regex
def to_python(self, value):
return value
def to_url(self, url):
return url
//添加转换器
app.url_map.converters['re'] = RegexConverter
//应用 根据正则表达式匹配对应的参数
app.route('/send/<re(r'1[345678]\d{9}'):mobile>')
def send_mobile(mobile):
return 'mobile is %d' % mobile
11、request data、form、args、values、files、json
前端from表单
application/x-www-form-urlencoded 与后端交互默认值
multipart/form-data 一般用于上传包含图片文件的数据
text/plain 发送纯文本数据
当请求没有设置Content-Type:application/json时,Body里面的数据都会放到request.data
当请求有设置Content-Type:application/json时,Body里面的数据都会放到request.json
获取queryString参数用request.args
request.form 接收表单数据 request.form.getlist() 获取多个重名参数列表
request.value 替代form和args
request.files 获取form中的文件
12、上传文件
f = request.file.get(‘name’)
f.save('url')
//save函数过程
file_obj = request.file.get('name')
f = open('./url.jpg','wb')
data = dile_obj.read()
f.write(data)
f.close()
13、abort函数、自定义异常处理函数
abort(404) 提前终止函数,并返回状态404
自定义异常处理函数
@app.errorhandler(404)
def handle_error_404(error):
return error
14、返回自定义信息
from flask import Flask, jsonify
import json
app = Flask(__name__)
@app.route('/')
def index():
data = {
"name":"sgr","age":'"18"
}
json_str = json.dumps(data)
return json_str , 200, {"Content-Type":"application/json"} //返回页面信息 状态码 响应头信息
return jsonify(json_str) //等价于上一行
if __name__ == '__main__':
app.run()
15、设置、读取、删除cookie信息
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/set_cookie')
//设置cookie信息 其实是通过传递响应头信息的方式
def set_cookie():
resp = make_response('set cookie')
resp.set_cookie("name", "sgr", max_age = 3600)
resp.headers["Set-Cookie"] = "name=sgr"
return resp
@app.route('get_cookie')
def get_cookie():
cookie_msg = request.cookies.get("name")
return cookie_msg
//删除cookie函数 是修改过期时间的方式
def del_cookie():
resp = make_response('del_cookie')
resp.delete_cookie('name')
return resp
if __name__ == '__main__':
app.run()
16、session机制
from flask import Flask,session
app = Flask(__name__)
app.config['SECRET_KEY'] = 'skhsjjsgdjshsgssj' //设置session信息必须设置secret_key
@app.route('/login')
def login():
session['name'] = 'sgr'
session['mobile'] = 'xxx'
return 'session'
@app.route('/index')
def index():
name = session.get("name")
return name
if __name__ == '__main__':
app.run()
session第一次登录的时候并没有session_id,登陆以后session_id返回给浏览器,之后每次交互,都会带着session信息
session信息是保存再服务器端的数据,cookie保存在前端,cookie信息不安全,但是flask是把session信息保存在了session中,也不安全,flask通过secret_key将保存的 session信息进行了混淆处理,当发现改变时失效
如果session信息保存再机器内存中,服务器集群负载均衡,分发任务,可能既不会发送给之前存储session信息的机器,此时不存在session信息,这种一般根据地区进行分发,可以得到解决
线上会使用专门的redis机器,进行存储信息,此时不论引导到哪个机器,都只有一个数据源
如果没有cookie保存session_id,可以通过登录重定向,通过url进行保存信息(部分国家认为cookie是私有信息,需要授权),部分网站会有sid属性,无法设置有效时长
17、钩子函数
from flask import Flask
app = Flask(__name__)
@app.before_first_request()
def before_first_request():
print('第一次请求前')
@app.before_request()
def before_request():
print('执行请求之前')
@app.after_request(response)
def after_request():
print('执行请求之后')
return response
@app.teardown_request(response) //调试模式不执行
def teardown_request():
return response
if __name__ == '__main__':
app.run()
18、应用上下文 current_app、g
一次请求内多个函数之间参数传递
19、flask-script (runserver 和 shell)
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
manager = Manager(app = app)
@app.route('/')
def index():
return 'index page'
if __name__ == '__main__':
manager.run()
启动命令
python3 demo.py runserver
启动参数
-r(reload 重启)-d(debug 调试模式) -th(多线程) -p(port 端口) -h(host 域名)
20、模版与自定义过滤器
data = {
name:'sgr',
age:'18'
}
render_template('index.html', **data ) //模板路径和数据数据
render_template('index.html', name='sgr', age='18') //模板路径和数据数据
内置过滤器
safe 禁止转义
capitalize 首字母大写
lower 小写
upper 大写
title 每个单词首字母大写
trim 去除左右空格
reverse 字符串反转
striptage 去除html标签
format 格式化输出( {{ "%s is %d" | format("name",18) }} )
自定义过滤器
def fliter_step2( list ):
return list[::2]
app.add_template_filter(filter_step2, list2) //参数:(函数名称,作为过滤器的名称)
21、flask-wtf
模型类表单使用 demo.py
demo
22、宏
定义
{% macro input() %}
<input type= "text"
name = "username"
value= ""
size = "30">
{% endmacro %}
使用
{{ input() }}
外部导入
{% import "macro_input.html" as m_input %}
调用
{% m_input.input() %}
23、flash(闪现)
引入
from flask import Flask,flash
@app.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] != app.config['USERNAME']:
error = 'Invalid username'
elif request.form['password'] != app.config['PASSWORD']:
error = 'Invalid password'
else:
session['logged_in'] = True
flash('You were logged in')
return redirect(url_for('index'))
return render_template('login.html', error=error)
获取
{% for message in get_flashed_messages()
{{message}}
{% endfor %}
flash和它的名字一样,是闪现,意思就是我们的消息只会显示一次,当我们再次刷新也面的时候,它就不存在了,而正是这点,它经常被用来显示一些提示消息,比如登陆之后,显示欢迎信息等
24、sqlalchemy
pip install flask-sqlalchemy
pip install flask-mysqldb
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import func
app = Flask(__name__)
class Config():
SQLALCHEMY_DATABASE_URI = 'mysql://root:mysql@127.0.0.1:3306/test'
# mysql://用户名:密码@127.0.0.1:3306/数据库名
SQLALCHEMY_TRACK_MODIFICATIONS = True
# True 让数据库里面的数据和模型数据库里面的数据保持一致
SQLALCHEMY_ECHO = True
app.config.from_object(Config)
db = SQLAlchemy(app)
class User(db.Model):
__tablename__ = "tbl_users"
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(64), unique = True)
email = db.Column(db.String(128), unique = True)
password = db.Column(db.String(128))
role_id = db.Column(db.Integer, db.ForeignKey("tbl_roles.id"))
class Role(db.Model):
__tablename__ = "tbl_roles"
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(32), unique = True)
users = db.relationship("User", backref = "role")
def __repr__(self):
return "Role Object name=%s" % self.name
if __name__ == '__main__':
db.create_all() //创建所有数据库
role1 = Role(name = "admin") //创建用户
增加数据
user1 = User(name="sgr",email="xxx.com",password="xxx",role_id=role1.id)
db.session.add(role1) //添加数据
db.session.add_all(role1, role2, role3) //批量添加数据
db.session.commit() //提交数据库
查询数据
Role.query.all() //查询数据
db.session.query(Role).all() //
Role.query.first() //查询一条数据
Role.query.get('1') //查询一条数据(主键)
Role.query.filter_by(name = "wang", role_id = 1).all()
Role.query.filter(User.name == "wang", User.role_id == 1).all() // 与上面等价
Role.query.filter(or_(User.name == "wang", User.email.endswith("163.com"))).all() //或查询
Role.query.filter().offset().limit().order_by(User.id.desc()).all() //链式顺序
db.session.query(User.role_id, func.count(User.role_id)).group_by(User.role_id).all()
select role_id, count(role_id) from User group by role_id
修改数据
1)、 user = db.session.query(User).get(1)
user.name = 'python'
db.session.add(user)
db.session.commit()
2)、db.session.query(User).filter_by(name="zhou").update({"name":"python"})
db.session.commit()
删除数据
user = db.session.query(User).get(1)
db.session.delete(user)
db.session.commit()
//案例
25、migrate扩展
https://www.jianshu.com/writer#/notebooks/49587685/notes/85758743
26、flask-blueprint
main.py
from flask import Flask
from goods import app_goods
from user import register
app = Flask(__name__)
app.register_blueprint(app_goods, url_prefix="/goods")
app.route('/user')(register)
@app.route('/')
def index():
return 'index'
if __name__ == "__main__":
app.run()
user.py
def register():
return 'register'
goods.py
from flask import Blueprint
app_goods = Blueprint("app_goods", __name__)
@app_goods.route('/get_goods')
def get_goods():
return 'get_goods page'
27、以目录的结构定义蓝图
文件目录
main.py
from flask import Flask
from flask_script import Manager
from cart import app_cart
app = Flask(__name__)
manager = Manager(app=app)
app.register_blueprint(app_cart, url_prefix="/cart")
if __name__ == '__main__':
manager.run()
__init__.py
from flask import Blueprint
app_cart = Blueprint("app_cart", __name__)
from .views import get_cart
views.py
from . import app_cart
@app_cart.route("/get_cart")
def get_cart():
return 'get_cart'
28、断言
assert isinstance(num, int)
29、单元测试
login.py
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/login', methods=['POST'])
def login():
username = request.form.get("username")
password = request.form.get("password")
if not all([username, password]):
resp = {
"code":0,
"msg":"invalide params"
}
return jsonify(resp)
if uasename == "name" and password == "python":
resp = {
"code":1,
"msg":"login success"
}
return jsonify(resp)
else:
resp = {
"code":2,
"msg":"username or password is not right"
}
return jsonify(resp)
if __name__ == '__main__':
app.run()
接口测试
test.py
import unittest
from login import app
import json
class LoginTest(unittest.TestCase):
def setUp(self): //相当于__init__函数
self.client = app.test_client()
app.testing = True //打开测试模式,可以查看具体的错误信息
def test_username_empty(self):
ret = self.client.post("/login", data = {})
resp = ret.data
resp = json.loads(resp)
self.assertIn("code", resp)
self.assertEqual(resp["code"],0)
if __name__ == '__main__':
unittest.main()
数据库操作
database.py
import unittest
from author_book import db, app, Author
class DatabaseTest(unittest.TestCase):
def setUp(self):
self.testing = True
self.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:password@127.0.0.1:3306/test"
db.create_all()
def test_add_author(self):
author = Author(name="zhang", email="1057@qq.com", mobile="13678787878")
db.session.add(author)
db.session.commit()
result = db.session.query(Author).filter_by(name="zhang").first()
self.assertIsNotNone(result)
def teardown(self):
db.session.remove()
db.drop_all()
30、部署(nginx + gunicorn + flask)
gunicorn
pip install gunicorn
gunicorn -h (帮助信息)
启动命令
gunicorn -w 4 -b 127.0.0.1:5000 -D --access-logfile ./logs/access_log main:app
-w 开启子进程
-b 当前服务器绑定到哪个ip、端口
-D 守护进程对方式运x行
--access-logfile ./logs/ 日志信息
main:app main.py中的app对象
ps aux | grep gunicorn 查看gunicorn进程
kill -9 进程id号 杀死进程
nginx
安装启动命令 mac
https://blog.csdn.net/weixin_39788856/article/details/94540125
配置文件