比较简单易懂的flask入门教程:https://read.helloflask.com/
详细教程:http://www.imooc.com/wiki/flasklesson/flaskredis.html
flask安装:
方法一:pip install flask --timeout=99999 # 延迟超时时间
方法二:pip install flask -i https://pypi.tuna.tsinghua.edu.cn/simple # 换源
源码安装:
python setup.py install
验证安装成功:
import flask
flask.__version__
第一个flask程序:
# 程序结构
.
└── app.py
0 directories, 1 file
# app.py
from flask import Flask
app = Flask(__name__) # name 主模块或包的名称,根据这个文件找到其他文件的位置
@app.route('/index')
@app.route('/') # 路由配置
def hello_world():
return 'hello world'
MTV模型:
m:模型 与数据库相关
t:模板 html
v:视图 函数
启动服务器:
-设置环境变量: export FLASK_APP = app.py
-启动内置web服务器: flask run
修改ip:
flask run --host=0.0.0.0 --port=8001
# 127.0.0.1 -eq localhost
# 0.0.0.0 -eq 本地ip,需要同一个局域网
开启调试:
export FLASK_ENV=development
# Debug mode: on
生产环境:Environment: production
调试环境:Environment: development
URL:统一资源定位符,是互联网上标准资源的地址
包含了协议,IP地址,路径和文件名
常用协议:http, https, ftp
常见的http请求方式:
GET: 可以用浏览器直接访问;请求可以携带参数,但对长度有限制
POST:不能用浏览器直接访问;可以用来上传文件等需求
常见状态码:
2xx:请求成功
3xx:重定向
4xx:请求错误
5xx:服务器错误
@app.route('/index')
@app.route('/user/<username>') # 传递参数,默认为string
@app.route('/user/<int:username>') # 指定参数类型
查看路由规则列表:
print(app.url_map)
---
Map([<Rule '/index' (GET, OPTIONS, HEAD) -> hello_world>,
<Rule '/hello' (GET, OPTIONS, HEAD) -> hello>,
<Rule '/' (GET, OPTIONS, HEAD) -> hello_world>,
<Rule '/static/<filename>' (GET, OPTIONS, HEAD) -> static>])
参数传递:
@app.route('/user/')
@app.route('/user/<page>')
def list_user(page=1):
return 'no {}'.format(page)
请求报文:
获取get参数:|
from flask import request
@app.route('/test/req')
def test_request():
get_args = request.args
print(get_args)
print(get_args.get('a', 'def'))
return 'request success'
# http://localhost:5000/test/req?a=1&b=2
# 所有的参数显示为 ImmutableMultiDict([('a', '1'), ('b', '2')])
# http://localhost:5000/test/req?
# 获取 'a'的值时, 显示def
解析请求头中的IP地址:
# 服务器所在的主机地址
headers = request.headers
print(headers)
# Host: 127.0.0.1:5000
# Connection: keep-alive
# Cache-Control: max-age=0 ...
print(headers.get('host'))
# 127.0.0.1:5000
# ip地址
ip = request.remote_addr
print('远程IP地址')
print(ip)
# User-Agent: 用户信息
user_agent = headers.get('user-agent', None)
print(user_agent)
请求钩子:减少重复代码的编写;ip拦截 # 是不是类似setup, teardown
@app.before_first_request
def first_request():
# 服务器启动的第一个请求
print('first request')
@app.before_request
def per_request():
# 每一个请求到达前
print('before each request')
# after_request 请求完成后执行,若出现异常不执行
# teardown_request 请求完成后执行,若出现异常也执行
响应报文:
@app.route('/test/resp')
def test_response():
# 指定响应内容,指定响应状态码,响应头信息
return 'response success', 201, {'user_id': 121212}
重定向:用于登录、退出的场景
@app.route('/') # 路由配置
def hello_world():
from flask import redirect
# redirect
return redirect('/user')
@app.route('/user/')
@app.route('/user/<page>')
def list_user(page=1):
return 'no {}'.format(page)
# 打开‘/’后会重定向到/user/
触发异常:
from flask import abort
(简单粗暴款)
@app.route('/') # 路由配置
def hello_world():
# return redirect('/user')
abort(403) # 满足某种条件后触发异常
(精致款)
@app.errorhandler(403)
def forbidden_page(err):
print(err)
return 'error info'
模板:
.
├── app.py
├── __pycache__
│ └── app.cpython-37.pyc
└── templates
└── index.html
2 directories, 3 files
@app.route('/html_page')
def html_test():
return render_template('index.html')
渲染:
@app.route('/html_page')
def html_test():
from datetime import datetime
now_time = datetime.now().strftime('%Y%m%d%H%M%S')
return render_template('index.html', time=now_time)
# html
<h1 style="color: #f00"> {{ time }} </h1>
默认的模板引擎:Jinja2
数据类型:
# index.html
<h1> {{ time }} </h1>
<h2> {{ age }} </h2>
<h2> {{ name }} </h2>
<p>
{{ user_info.username }}
{{ user_info.nickname }}
{{ user_info["add.city"] }}
{{ user_info["add.area"] }}
<br/>
{{ tuple_city[0] }}
{{ list_city[0] }}
<br/>
{{ list_user[0].username }}
</p>
# app.py
age = 20
name = 'qwqwqw'
user_info = {
"username": "zhangshan",
"nickname": "asasas",
"add.city": "GZ",
"add.area": "th"
}
tuple_city = ('bj', 'sh', 'nj')
list_city = ['bj', 'sh', 'nj']
list_user = [
{
"username": "q",
"age": 1
},
{
"username": "w",
"age": 2
},
]
return render_template('index.html', time=now_time, age=age, name=name,
user_info=user_info, tuple_city=tuple_city,
list_city=list_city, list_user=list_user)
PS:引号的单双混用,显得代码很脏,有空改改
# 变量
{{ name }}
# 语法
{% tag %}
内容
{% endtag %}
# 注释
{# xxxx #}
{% if cond_a %}
{% elif cond_b %}
{% else %}
{% endif %}
{% for i in user_name %}
<p> {{ i.username }} - {{ i.age }} </p>
{% else %}
<p> 121212 </p>
{% endfor %}
"""
for xxxx in xxx:
xxx
else:
xxx
# 循环结束后执行else
"""
什么是宏:把常用的功能抽取出来,实现可重用;简单理解为函数
{% xxxxxx -%}
这样加一个 - ,可以去除html中空行,节省一些资源
---macro.html
<!-- 带参数 -->
{% macro input2(name, type="", value="", size=30) %}
<input type="{{ type }}" name="{{ name }}" value="{{ value }}" size="{{ size }}">
{% endmacro %}
---macro1.html
{% from 'macro.html' import input2 with context %}
<p>输入用户名:{{ input2('username', value=username, type='text', size=20) }}</p>
---app.py
context={
'username': '老萝卜',
'age': 18
}
@app.route("/")
def demo_marco1():
return render_template('macro1.html', **context)
PS:此处参考自:https://blog.csdn.net/laoluobo76/article/details/109114925#commentBox
模板的继承,效果如图:
base.html
<body>
{% block content %}
此处为可替换内容
{% endblock %}
</body>
a.html
{% extends 'base.html' %}
{% block content %}
此处为扩展后的内容
{% endblock %}
b.html
{% extends 'base.html' %}
{% block content %}
此处为扩展后的内容2
{% endblock %}
{% extends 'base.html' %}
{% block content %}
{{ super() }}
<p>这是扩展后的页面</p>
{% endblock %}
# 使用super() 可以保留通用模板的内容,而不会替换掉,
# 网页显示为
‘’‘
此处为可替换内容
这是扩展后的页面
’‘’
模块中的包含:
ba.html
{% extends 'base.html' %}
{% block content %}
这是扩展后的页面2
{% include 'new.html' %}
{% endblock %}
new.html
<p> new add </p>
效果图片如下:
flask的orm: 对象关系的映射
# 安装flasksqlalchemy:
pip install -U FlaskAlchemy
# 安装其他依赖
pip install mysqlclient
app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
user = 'root'
password = '123456'
database = 'school'
uri = 'mysql+pymysql://%s:%s@localhost:3306/%s' % (user, password, database)
app.config['SQLALCHEMY_DATABASE_URI'] = uri
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class User(db.Model):
__tablename__ = 'users'
userId = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255))
password = db.Column(db.String(255))
之后在终端输入:
>>> from app import db
>>> from app import User #这个要注意,一定要导入模型,否则创建数据库失败
>>> db.create_all() # 在数据库中创建 users 表结构
>>> db.drop_all() # 在数据库中删除 users 表结构
数据的增加修改物理删除:
>>> user = User(id=1,username='za', password='123') # 新增
>>> user2 = User(id=2,username='1za', password='1223',birth_date='2020-01-01')
>>> db.session.add(user)
>>> db.session.commit()
>>> db.session.add(user2)
>>> db.session.commit()
>>>> user2.id # 查询
2
>>> user2.age
0
>>> user2.username='qwerty' # 修改
>>> db.session.add(user2) # 类似git的add吧
>>> db.session.commit() # 提交
>>> db.session.delete(user2) # 删除一条物理数据
>>> db.session.commit()
数据的查询:
>>> all_user = User.query.all() # 查询所有的记录
>>> all_user
[<User 1>, <User 2>]
>>> q = User.query.filter_by(username='za') # 根据用户名查询
>>> q
<flask_sqlalchemy.BaseQuery object at 0x7fb4be21d518>
>>> q[0]
<User 1>
>>>
>>> w = User.query.get(1) # 获取第一个
>>> w
<User 1>
>>> w = User.query.first() # 获取第一个
>>> w
<User 1>
>>> w = User.query.get_or_404(3) # 获取不到则返回404页面
flask 的表单:
表单标签: <form> </form>
安装: pip install Flask-WTF -i https://pypi.tuna.tsinghua.edu.cn/simple
配置CSRF保护: app.config['WTF_CSRF_SECRET_KEY']='A random string'
(如果有消息闪现的话,再配置一下这个)app.config['SECRET_KEY'] = 'hard to guess string'
formpage.html
<form action="" method="post">
{{ form.username.label}}
{{ form.username }}
</form>
app.py
from flask import Flask
from flask import render_template
from flask_wtf import FlaskForm
from wtforms import StringField
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
class LoginForm(FlaskForm):
username = StringField(label='用户名:')
@app.route('/formpage', methods=['get', 'post'])
def form_page():
form = LoginForm()
return render_template('index.html', form=form)