Flask基础知识点总结(一),新手必看!!!
Flask基础分为三个阶段,此版本为你第一版,后续请各位同学继续关注!!!
#1Flask的搭建环境及使用,以及视图函数的用法
使用pip install Flask 指令进行扩展包的安装
在Pycharm中使用 from flask import Flask进行导入
基本的模型为:
from flask import Flask
app = Flask(__name__)
@app.route('/')#指定路由地址
def index():
return 'hello world'
if '__name__'=='__main__':
app.run()#启动服务
#2视图的常用逻辑
2-1 返回JSON
#在使用 Flask 写一个接口时候需要给客户端返回 JSON 数据,
#在 Flask 中可以直接使用 jsonify 生成一个 JSON 的响应
# 返回JSON
@app.route('/demo4')
def demo4():
json_dict = {
"user_id": 10,
"user_name": "laowang"
}
return jsonify(json_dict)
2-2 重定向 使用redirect模块
@app.route(/123)
def demo():
return redirect('http://www.baidu.com')
# 异常捕获
HTTP 异常主动抛出,abort方法‘abort(500)’,给定一个状态码
捕获错误 errorhandler
from flask import Flask
app = Flask(__name__)
@app.errorhandler(500)
def index(e):
return '服务器找不到了'
@app.errorhandler(ZeroDivisionError)
def zero(e):
return '除数不能为0'
if '__name__'=='__main__':
app.run()
Cookie
客户端和服务端进行会话保持的一种技术
cookies保存在客户端,具体的数据是每次访问服务器后,服务器通过响应头的set_cookies字段告诉浏览器,需要将指定的数据保存在cookies中,并且浏览器下一次发起请求时,会自动将cookies中的数据写入请求头的Cookie字段中传给浏览器
cookies的存储具有一定的有效期,并且时同源策略(浏览器只会携带百度的cookies传给百度服务器)
user_data = {}
@app.route("/")
def index():
# 获取cookie
id = request.cookies.get("user_id")
if id:
name = user_data[id]
return "welcome %s" % name
else:
return "请登陆"
@app.route("/user", methods=['POST', "GET"])
def user():
# 获取参数
name = request.args.get('name', "")
id = request.args.get("id", "")
# 保存数据
user_data[id] = name
# 构造响应
resp = make_response("登陆完成")
# 设置cookie
resp.set_cookie("user_id", id)
return resp
session
将用户信息直接存储在Cookie中并不安全,可以考虑将用户信息存储到服务器中,并且加密存储,只把存储位置放入cookies中,以后浏览器通过携带cookies中存储位置找到对应数据
from flask import session
使用session必须设置secret_key
app.secret_key = "itcast"
@app.route("/")
def index():
session['user_name'] = "张三"
session['id'] = 123
return "success"
勾子函数
#Flask支持四种请求勾子
<!--# before_first_request:-->
<!--在处理第一个请求前执行-->
<!--before_request:-->
<!--在每次请求前执行-->
<!--如果在某修饰的函数中返回了一个响应,视图函数将不再被调用-->
<!--after_request:-->
<!--如果没有抛出错误,在每次请求后执行-->
<!--接受一个参数:视图函数作出的响应-->
<!--在此函数中可以对响应值在返回之前做最后一步修改处理-->
<!--需要将参数中的响应在此参数中进行返回-->
<!--teardown_request:-->
<!--在每次请求后执行-->
<!--接受一个参数:错误信息,如果有相关错误抛出-->
from flask import Flask
from flask import abort
app = Flask(__name__)
# 在第一次请求之前调用,可以在此方法内部做一些初始化操作
@app.before_first_request
def before_first_request():
print("before_first_request")
# 在每一次请求之前调用,这时候已经有请求了,可能在这个方法里面做请求的校验
# 如果请求的校验不成功,可以直接在此方法中进行响应,直接return之后那么就不会执行视图函数
@app.before_request
def before_request():
print("before_request")
# if 请求不符合条件:
# return "laowang"
# 在执行完视图函数之后会调用,并且会把视图函数所生成的响应传入,可以在此方法中对响应做最后一步统一的处理
@app.after_request
def after_request(response):
print("after_request")
response.headers["Content-Type"] = "application/json"
return response
# 请每一次请求之后都会调用,会接受一个参数,参数是服务器出现的错误信息
@app.teardown_request
def teardown_request(e):
print("teardown_request")
@app.route('/')
def index():
return 'index'
if __name__ == '__main__':
app.run(debug=True)
自定义路由转化器
创建一个类,继承自BaseConverter
重写类的regex属性
添加到converters中:app.url_map.converters[‘re’] = ReConverter
创建一个通用的路由转化器
class ReConverter(BaseConverter):
def __init__(self, map, regex):
super(ReConverter, self).__init__(map)
self.regex = regex
app.url_map.converters['re'] = ReConverter
@app.route("/user/<re('[0-9]{2}'):user_id>")
def user(user_id):
return "用户id %s" % user_id
@app.route("/user/<re('[a-z]{6}'):user_name>")
def user2(user_name):
return "用户name %s" % user_name
CSRF攻击:跨站请求伪造,
1.用户在登陆存在漏洞的A网站后,网站会向用户的浏览器写入登陆凭证到Cookie中
2.用户在没有退出A网站的前提下,访问了B网站
B网站伪造了一个form表单,参数被设置为固定值,单action指向了A网站,当用户点击提交的时候,浏览器会自动向A网站发起请求,并携带伪造的参数信息和Cookies
3.A网站根据Cookies和参数信息做出响应
如果防止CSRF攻击?
4.A网站在下发form表单的时候,产生一个随机值放入表单中作为隐藏字段,同时将这个随机值写入Cookis
5.A网站在验证请求时,必须从form中能够取出隐藏字段的值,以及从cookies中也能取出写入的值,并且二者相同,认为是合法请求
在不使用flask-wtf表单的情况下,进行CSRF保护
集成flask-wtf
手动在form表单中设置隐藏字段,字段name为csrf_token
在上述代码中,由于以下原因,所以模板中的csrf_token()有效
app.jinja_env.globals[‘csrf_token’] = generate_csrf
在代码中开启保护
from flask_wtf import CSRFProtect
### 设置seeesion的**
app.secret_key = "itcast"
### 开启保护
CSRFProtect(app)
相关的配置参数
WTF_CSRF_ENABLED设置是否进行CSRF验证
WTF_CSRF_METHODS设置哪些方法的请求会进行CSRF验证,默认是['POST', 'PUT', 'PATCH', 'DELETE']
WTF_CSRF_FIELD_NAME 获取提交的csrf_token的值对应的字段名称
源码分析:
给seesion中设置一个csrf_token值
{"csrf_token":"d00418ddd6b434101c90fecf9268215774b82965"}
并将其进行base64加密后设置为G变量的csrf_token属性的值,并返回
def generate_csrf(secret_key=None, token_key=None):
# 获取**
secret_key = _get_config(
secret_key, 'WTF_CSRF_SECRET_KEY', current_app.secret_key,
message='A secret key is required to use CSRF.'
)
# 获取存储csrf_token值的键
field_name = _get_config(
token_key, 'WTF_CSRF_FIELD_NAME', 'csrf_token',
message='A field name is required to use CSRF.'
)
if field_name not in g:
if field_name not in session:
"""
在session中设置一串64位长度的字符串并进行hashlib.sha1加密,返回一个40位长度的字符串作为token值
"""
session[field_name] = hashlib.sha1(os.urandom(64)).hexdigest()
s = URLSafeTimedSerializer(secret_key, salt='wtf-csrf-token')
# 给g变量设置一个属性,csrf_token=Base64(token值)
setattr(g, field_name, s.dumps(session[field_name]))
return g.get(field_name)
当用户提交form表单时,会进行验证:
@app.before_request
def csrf_protect():
if not app.config[‘WTF_CSRF_ENABLED’]:
return
if not app.config['WTF_CSRF_CHECK_DEFAULT']:
return
# 只会验证post请求,get请求直接放行
if request.method not in app.config['WTF_CSRF_METHODS']:
return
if not request.endpoint:
return
view = app.view_functions.get(request.endpoint)
if not view:
return
if request.blueprint in self._exempt_blueprints:
return
dest = '%s.%s' % (view.__module__, view.__name__)
if dest in self._exempt_views:
return
self.protect()
def protect(self):
if request.method not in current_app.config['WTF_CSRF_METHODS']:
return
try:
# 从form表单中获取name为csrf_token的值和seesion中存储的csrf_token进行对比验证
validate_csrf(self._get_csrf_token())
except ValidationError as e:
logger.info(e.args[0])
self._error_response(e.args[0])
if request.is_secure and current_app.config['WTF_CSRF_SSL_STRICT']:
if not request.referrer:
self._error_response('The referrer header is missing.')
good_referrer = 'https://{0}/'.format(request.host)
if not same_origin(request.referrer, good_referrer):
self._error_response('The referrer does not match the host.')
def validate_csrf(data, secret_key=None, time_limit=None, token_key=None):
secret_key = _get_config(
secret_key, 'WTF_CSRF_SECRET_KEY', current_app.secret_key,
message='A secret key is required to use CSRF.'
)
field_name = _get_config(
token_key, 'WTF_CSRF_FIELD_NAME', 'csrf_token',
message='A field name is required to use CSRF.'
)
time_limit = _get_config(
time_limit, 'WTF_CSRF_TIME_LIMIT', 3600, required=False
)
if not data:
raise ValidationError('The CSRF token is missing.')
if field_name not in session:
raise ValidationError('The CSRF session token is missing.')
s = URLSafeTimedSerializer(secret_key, salt='wtf-csrf-token')
try:
# 将form表单的中csrf_token的值进行base64解码,返回的时一个40位长度的字符串
token = s.loads(data, max_age=time_limit)
except SignatureExpired:
raise ValidationError('The CSRF token has expired.')
except BadData:
raise ValidationError('The CSRF token is invalid.')
# 将token和sesison中的csrf_token的值进行对比
if not safe_str_cmp(session[field_name], token):
raise ValidationError('The CSRF tokens do not match.')
模板的使用 template
1.在项目下创建 templates 文件夹,用于存放所有的模板文件,并在目录下创建一个模板html文件 temp_demo1.html
2.设置 templates 文件夹属性以便能够在代码中有智能提示
3.设置 html 中的模板语言,以便在 html 有智能提示
4.创建视图函数,将该模板内容进行渲染返回
@app.route('/')
def index():
return render_template('temp_demo1.html')
5.代码中传入字符串,列表,字典到模板中
@app.route('/')
def index():
# 往模板中传入的数据
my_str = 'Hello 黑马程序员'
my_int = 10
my_array = [3, 4, 2, 1, 7, 9]
my_dict = {
'name': 'xiaoming',
'age': 18
}
return render_template('temp_demo1.html',
my_str=my_str,
my_int=my_int,
my_array=my_array,
my_dict=my_dict
)
6.模板中的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
我的模板html内容
<br/>{{ my_str }}
<br/>{{ my_int }}
<br/>{{ my_array }}
<br/>{{ my_dict }}
</body>
</html>
Jinjia2 中的If语句和for循环(控制代码块)
if语句
{%if user.is_logged_in() %}
<a href='/logout'>Logout</a>
{% else %}
<a href='/login'>Login</a>
{% endif %}
过滤器可以被用在 if 语句中:
{% if comments | length > 0 %}
There are {{ comments | length }} comments
{% else %}
There are no comments
{% endif %}
循环
Jinja2 中使用循环来迭代任何列表或者生成器函数
{% for post in posts %}
<div>
<h1>{{ post.title }}</h1>
<p>{{ post.text | safe }}</p>
</div>
{% endfor %}
循环和if语句可以组合使用,以模拟 Python 循环中的 continue 功能,下面这个循环将只会渲染post.text不为None的那些post:
{% for post in posts if post.text %}
<div>
<h1>{{ post.title }}</h1>
<p>{{ post.text | safe }}</p>
</div>
{% endfor %}
模板继承 extends
父模板
#base.html
{% block top %}
顶部菜单
{% endblock top %}
{% block content %}
{% endblock content %}
{% block bottom %}
底部
{% endblock bottom %}
子模板
{% extends 'base.html' %}#extends声明这个模板继承自哪
{% block content %}
需要填充的内容
{% endblock content %}
蓝图,readis
蓝图
1.创建一个蓝图对象
admin=Blueprint('admin',__name__)
2.在这个蓝图对象上进行操作,注册路由,指定静态文件夹,注册模版过滤器
@admin.route('/')
def admin_home():
return 'admin_home'
3.在应用对象上注册这个蓝图对象
app.register_blueprint(admin,url\_prefix='/admin')
Readis非关系型数据库/基础指令的操作/与python的交互
readis的数据操作
1.String
```python
设置键值
set key value
set name itlgg
eg:设置键名name值为itgg
设置键值及过期时间,以秒为单位
setx key seconds value
setx aa 3 aa
eg:设置键为aa值为aa过期时间为3秒的数据
设置多个键值
mset key1 value1 key2 value
mset a1 python a2 java a3 c
eg:设置键为'a1'值为'python'、键为'a2'值为'java'、键为'a3'值为'c'
追价值
append key value
append 'a1' 'haha'
eg:向键为a1中追加值' haha'
```
获取
获取:根据键获取值,如果不存在此键则返回nil
get key
get 'name'
eg:获取键'name'的值
根据多个键获取多个值
mget key1 key2 ...
mget a1 a2 a3
eg:获取键a1、a2、a3'的值
2.set
添加元素
sadd key member1 member2 ...
sadd a3 zhangsan sili wangwu
eg:向键'a3'的集合中添加元素'zhangsan'、'lisi'、'wangwu'
返回所有的元素
smembers key
smembers a3
eg:获取键'a3'的集合中所有元素
删除指定元素
srem key
srem a3 wangwu
eg:删除键'a3'的集合中元素'wangwu'
上一篇: 初学cloud的第一天
下一篇: 切片与字典(Python day 11)
推荐阅读
-
Python基础总结之第八天开始【while循环以及for循环,循环嵌套等循环相关的知识点】(新手可相互督促)
-
Python基础总结之第一天(新手可相互督促)
-
Flask基础知识点总结(一),新手必看!!!
-
给Java新手的一些建议——Java知识点归纳(Java基础部分)
-
HTML5基础知识点总结(一)
-
Python基础总结之第十天开始【认识一下python的另一个数据对象-----字典】(新手可相互督促)
-
新手必看的PHP学习入门的一些基础知识
-
新手必看的PHP学习入门的一些基础知识_PHP教程
-
Python基础总结之第八天开始【while循环以及for循环,循环嵌套等循环相关的知识点】(新手可相互督促)
-
新手必看的PHP学习入门的一些基础知识_PHP教程