自动导包:option+enter(mac)ctl+enter(windows)
查看传参:ctr+ p
新增文件:ctr + n
1、hello_worldfrom flask import Flask
# 创建应用对象
# __name__:如果程序直接在当前文件执行,值为__main__,如果从其他文件调用执行,表示模块名称
# static_url_path:静态资源路径默认为:./static
#template_folder: 模板路径,默认为:./templates
app = Flask(__name__)
# 使用路由路径,绑定视图函数
@app.route('/')
def hello_world():
return 'hello world!'
if __name__ == '__main__':
app.run()
这是flask框架最简单的一段代码,以及其中参数的含义
1、如果一个路由装饰多个函数,那么访问的是哪个函数?
访问先被装饰的函数,相当于一个队列,先进先出
2、如果一个视图函数由多个路由装饰,那么优先访问哪个路径?
所有的路径都能访问视图函数
2、methods若一个路由装饰多个函数,可以通过methods,确认请求方式来确认访问的视图函数.methods 是一个列表,不同请求方式使用逗号分割
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'hello world!'
@app.route('/', methods=["post"])
def hello_world2():
return 'hello world2!'
if __name__ == '__main__':
app.run()
3、url_for
url_for 是属于app的方法,在flask模块中
格式:url_for('试图函数名字', key=value)
可以通过视图函数找到对应的路由路径,用于服务器内部资源定位,常与redirect连用
使用url_for传递参数时,接受的参数名需要与传递的参数名一致
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'hello world点击按钮'.format(url_for('hello_world2'))
@app.route('/index')
def hello_world2():
return 'hello world2!'
if __name__ == '__main__':
app.run()
传参:
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'hello world点击按钮'.format(url_for('hello_world2', money=100))
@app.route('/index/')
def hello_world2(money):
return 'hello world2!,钱数:{}'.format(money)
if __name__ == '__main__':
app.run()
4、redirect
重定向,可以通过路由找到视图函数,并自动跳转执行
格式:redirect('路径'),常与url_for一起使用
from flask import Flask, url_for, redirect
app = Flask(__name__)
@app.route('/')
def hello_world():
return redirect(url_for('hello_world2', money=100))
@app.route('/index/')
def hello_world2(money):
return 'hello world2!,钱数:{}'.format(money)
if __name__ == '__main__':
app.run()
5、返回json数据
有两种方式:
a:通过jsonify(dict),flask模块中
b:json.dump() ,需要配合response对象设置,不推荐
from flask import Flask, url_for, redirect, jsonify
app = Flask(__name__)
@app.route('/')
def hello_world():
dict={
"name":"zhangsan",
"age":19
}
return jsonify(dict)
if __name__ == '__main__':
app.run()
在浏览器控制台可以看到响应头的conten-type是json格式
使用json.dumps()
from flask import Flask, url_for, redirect, jsonify, json, make_response
app = Flask(__name__)
@app.route('/')
def hello_world():
dict={
"name":"zhangsan",
"age":19
}
return json.dumps(dict)
if __name__ == '__main__':
app.run()
上面代码在浏览器返回的是text格式,若要返回json格式,还需要借助response对象
6、路由传参格式:app.route("路径/<数据类型:变量名>")
数据类型:
int:整数
float:小数
path:字符串
from flask import Flask, url_for, redirect, jsonify
app = Flask(__name__)
@app.route('/')
def hello_world(reasion):
return "我今天是因为{}迟到了!".format(reasion)
if __name__ == '__main__':
app.run()
但是没办法限制传参的个数,可以通过自定义转换器
之所以可以编写int、float、path是因为系统已经添加默认的转换器,如果要限制参数的具体个数等类型需要自定义
a、自定义类,继承自BaseConverter
b、重写__init__方法,接受两个参数,调用父类__init__方法初始化父类内容
c、将规则赋值到子类对象
d、将转换器添加到系统默认的转换器列表中
查看系统自带的转换器:app.url_map.converters
from flask import Flask, url_for, redirect, jsonify
from werkzeug.routing import BaseConverter
app = Flask(__name__)
class MyConvert(BaseConverter):
def __init__(self, url_map, regex):
super(MyConvert, self).__init__(url_map)
self.regex = regex
app.url_map.converters['re'] = MyConvert
@app.route('/')
def hello_world(number):
return "the phonenumber is {}".format(number)
if __name__ == '__main__':
app.run()
to_python 方法
from flask import Flask, url_for, redirect, jsonify
from werkzeug.routing import BaseConverter
app = Flask(__name__)
class MyConvert(BaseConverter):
def __init__(self, url_map, regex):
super(MyConvert, self).__init__(url_map)
self.regex = regex
# 重写to_python 方法
def to_python(self, value):
return 'xixi' + value
app.url_map.converters['re'] = MyConvert
@app.route('/')
def hello_world(number):
return "the phonenumber is {}".format(number)
if __name__ == '__main__':
app.run()
请求结果
在匹配完规则后,进入到视图函数之前执行该方法,可以过滤数据或编码 *** 作
7、调试模式在运行程序的时候,可以通过app.run(debug=True)进入调试模式,修改代码之后,保存,自动重新启动
好处:
a、程序改动之后,不需要重新启动既可以部署
b、如果程序报错,有友好提示界面
if __name__ == '__main__':
app.run(debug=True)
8、abort
主动停止程序,会配合@app.errorhandler使用,用来自定义错误界面
from flask import Flask, abort
app = Flask(__name__)
@app.route('/')
def hello_world():
abort(403)
return "hello world!!"
常与@app.errorhandler装饰器使用,可以自定义错误
from flask import Flask, abort
app = Flask(__name__)
@app.route('/')
def hello_world():
abort(404)
return "hello world!!"
@app.errorhandler(404)
def exception_404(e):
return "找不到资源"
if __name__ == '__main__':
app.run(debug=True)
##########################################################
from flask import Flask, abort
app = Flask(__name__)
@app.route('/')
def hello_world():
# abort(404)
raise(Exception("big error"))
return "hello world!!"
@app.errorhandler(404)
def exception_404(e):
return "找不到资源"
@app.errorhandler(Exception)
def exception(e):
return "出现大错误"
if __name__ == '__main__':
app.run(debug=True)
9、请求对象和返回对象
request:和请求对象相关,里面封装了请求有关的信息,比如请求方式、请求路径、请求参数
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def hello_world():
print(request.method)
print(request.url)
print(request.args)
return "hello world!"
if __name__ == '__main__':
app.run(debug=True)
###################################
# 响应:
# 127.0.0.1 - - [02/May/2022 13:26:02] "GET
# http://127.0.0.1:5000/?name=zhagnsan&age=13
# ImmutableMultiDict([('name', 'zhagnsan'), ('age', '13')])
# GET /?name=zhagnsan&age=13 HTTP/1.1" 200 -
响应对象,在后端返回数据的时候,有两种主要方式
直接返回
1、响应体 return “hello world”
2、响应体+状态码 return “hello world”,666
3、响应体+状态码+响应头 return “hello world”,666,{"Content-Type":"application/json"}
手动封装response对象返回
response = make_response(响应体)
response.status = "666"
response.hearder["Content-Type"] = "application/json"
10、请求勾子在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如:
- 在请求开始时,建立数据库连接;
- 在请求开始时,根据需求进行权限校验;
- 在请求结束时,指定数据的交互格式;
请求钩子是通过装饰器的形式实现,Flask支持如下四种请求钩子
before_first_request:在处理第一个请求前执行
before_request:每次请求前执行,如果在某修饰的函数中返回了一个响应,视图函数将不再被调用
after_request:如果没有抛出错误,在每次请求后执行;接受一个参数:视图函数作出的响应;在此函数中可以对响应值在返回之前做最后一步修改处理;需要将参数中的响应在此参数中进行返回
teardown_request:每次请求后执行,接受一个参数:错误信息,如果有相关错误抛出
11、cookie和sessionhttp 是一种无状态协议,浏览器请求服务器是无状态的,有时需要保持下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等
- 在客户端存储信息使用
Cookie
- 在服务器端存储信息使用
Session
设置cookie:当前浏览器访问服务器时,由服务器设置一些状态信息到浏览器中,存储在浏览器中
response.set_cookie(key,value,max_age) max_age: 过期时间
获取cookie:
request.cookies.get(key)
from flask import Flask, make_response, request
app = Flask(__name__)
@app.route('/set_cookie')
def set_cookie():
response = make_response()
response.set_cookie('name','zhangsan')
response.set_cookie('age',"13", 10)
return response
@app.route('/get_cookie')
def get_cookie():
name = request.cookies.get('name')
age = request.cookies.get('age')
return "name is {}, age is {}".format(name, age)
if __name__ == '__main__':
app.run(debug=True)
设置cookie
获取cookie
session: 当浏览器访问服务器的时候,由服务器创建并存储在服务器内部,依赖于cookie
一般用来存储用户的隐私数据,比如:密码信息,登录信息,yhk信息等
seesion数据设置过程:
1、当第一次请求的时候,在服务器端会给客户端设置响应的session数据,返回给客户端,存储在cookie中
2、当第二次发送请求是,cookie中会携带sessionID到服务器,通过ID可以获取到session中的数据
每一个用户向服务器请求的时候都会给其开辟对应的空间保存session数据
设置session:
session[key] = value
设置session的编号生成依赖于SECRE_KEY
获取session:
session.get(key) 若为空,直接返回空,推荐
session[key] 若为空,报错。不推荐
from flask import Flask, session
app = Flask(__name__)
app.config['SECRET_KEY'] = 'jhfjafjkd'
@app.route('/set_session/')
def set_session(name):
session['name'] = name
return '设置session成功'
@app.route('/get_session')
def get_session():
se = session.get('name')
return 'session is {}'.format(se)
if __name__ == '__main__':
app.run(debug=True)
12、flask_script 动态指定IP和端口
在时机开发中,项目封板之后,如果部署的服务器发生变化,意味着IP和端口可能出现变化,如果直接修改源代码风险比较大,而且繁琐,可以通过flask_script解决,可以动态指定运行的IP和端口
安装:
pip install flask-script
创建Manager对象,关联app应用程序对象
运行:python xxx.py runserver -h 127.0.0.1 -p 8888
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
# 设置调试模式
app.config["DEBUG"] = True
# 创建manager管理对象,关联app应用程序对象
manager = Manager(app)
@app.route('/')
def hello_world():
return "hello world"
if __name__ == '__main__':
# app.run(debug=True)
manager.run()
13、模板渲染
Flask中页面的渲染是通过jinja2模块来实现的,依赖于render_template函数
模板中的注释:{# #}
我们在编写模板时,变量都是没有提示的,设置步骤:
使用格式:
return render_temperate('模板文件',key=value)
将HTML文件渲染撑响应体对象,可以携带value值到页面中
模板的默认位置:templates,若没有该文件,报错
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
return render_template('file01.html')
if __name__ == '__main__':
app.run(debug=True)
模板中的常见语法
获取变量:{{变量名称}}
分支语句:{% if 条件A%}
语句1
{%elif 条件B%}
语句2
{%endif%}
循环语句:
{%for 变量 in 容器%}
语句
{%endfor%}
在HTML文件中若元祖或者列表取值时,可以使用list.0或者list[0],若是字典,可以dict.key
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
num = 3
str = '你好'
tuple = (10, 11, 12, 13)
list = [1, 2, 3, 4]
dict = {
"name":"张三",
"age":17
}
return render_template('file01.html', num=num, str=str, tuple= tuple, list=list, dict=dict)
if __name__ == '__main__':
app.run(debug=True)
Title
this is a template
整数:{{ num }}
字符串:{{ str }}
元祖:{{ tuple }}, 分开获取:{{ tuple.0 }}, {{ tuple[2] }}
列表:{{ list }}, 分开获取: {{ list.0 }}, {{ list[1] }}
字典:{{ dict }}, 分开获取: {{ dict.name }}, {{ dict.age }}
遍历列表中的偶数
{% for n in list %}
{% if n %2==0 %}
{{ n }}
{% endif %}
{% endfor %}
获取元祖的编号
{% for num in tuple %}
{# 索引:{{ loop.index0 }}, 值是:{{ num }} index0 表示从0开始,若是index,表示从1开始#}
索引:{{ loop.index0 }}, 值是:{{ num }}
{% endfor %}
遍历字典
{% for key in dict %}
{# {{ key }} = {{ dict[key] }} 不能通过dict.key来取值,这表示dict中有个主键是key,此时key不是一个变量#}
{{ key }} = {{ dict[key] }}
{% endfor %}
过滤器
常见的过滤器有两种:
字符串过滤器:
upper:将字符串转成大写
lower:将字符串转成小写
reverse:将字符串反转
2、列表过滤器
first:第一个元素
last:最后一个元素
sum:取和
sort:排序
使用方法:变量名|过滤器
14、模板复用宏:提前定义好模板代码块需要的时候调用即可
定义:{ % macro 宏名(参数) % }
{ % endmacro % }
{% macro input(name,value='',type='text') %}
{% endmacro %}
使用:
当前文件:{{宏名(参数)}}
其他文件:{ %import ”宏所在的文件“ as 别名% }
{% 别名.宏名(参数) %}
模板继承是为了重用模板中的公共内容,共性抽取,代码复用,继承之后可以扩展子模板独有的内容
{%extends "文件名"%}
包含:A完全用友B内容,一般对于不需要改变的内容使用包含
{%include "文件名" ignore missing%} #ignore missing如果文件不存在,不报错
模块的定义:
{%block 名称%}
{%endblock%}
继承
Title
{% extends 'file03fu.html' %}
15、flask表单
传统表单:有大量的HTML定义好的标签组成
缺点:一旦表单编写完成,如果需要增加额外的功能,就不能实现
传统表单
Title
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/')
def hello_world():
return render_template('file04nom.html')
@app.route('/register', methods=["post"])
def register():
print(request.form)
usrname =request.form.get('username')
password =request.form.get('password')
repassword =request.form.get('repassword')
if not all([usrname, password, repassword]):
return '没有填写必要内容'
if password != repassword:
return "密码不一致"
return '注册成功'
if __name__ == '__main__':
app.run(debug=True)
Flask_WTF:通过类的方式渲染页面,包含字段和验证函数
步骤:
- 安装,导包
- 自定义类,继承自FlaskForm
- 编写字段,验证函数
- 创建表单对象
- 渲染到页面中
包含csrf验证机制
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, PasswordField
from wtforms.validators import DataRequired, EqualTo
app = Flask(__name__)
app.config["SECRET_KEY"] = 'yhfjnfhhf'
# 自定义类,继承自FlaskForm
class MyForm(FlaskForm):
username = StringField('用户名', validators=[DataRequired()])
password = PasswordField('密码', validators=[DataRequired()])
repassword = PasswordField('确认密码', validators=[DataRequired(), EqualTo('password', '两次输入的密码必须一致!')])
submit = SubmitField('提交')
@app.route('/')
def hello_world():
# 创建表单
form = MyForm()
return render_template('file05wtf.html', form=form) #将form对象传递到模板文件中
@app.route('/register', methods=["post"])
def register():
# 根据创建的内容创建表单
form = MyForm()
# 验证提交的内容
if form.validate_on_submit():
return "注册成功"
return "注册失败"
if __name__ == '__main__':
app.run(debug=True)
HTML文件:
Title
16、数据库
常用的数据库命令:
# 进入mysql,回车输入密码
mysql -uroot -p
# 退出登录
quit
exit
ctrl+d
# 查看所有数据库
show databases;
# 使用数据库
use 数据库名;
# 删除数据库
drop 数据库名;
# 查看当前数据库中的所有表
show tables;
# 删除表
drop table 表名;
# 数据库备份
mysqldump -uroot -p 数据库名 > python.sql
# 数据库恢复
mysql -uroot -p 数据库名 < python.sql
flask *** 作数据库是通过库战报Flask_Sqlalchemy
*** 作流程:
- 安装,导入
pip install flask-sqlalchemy
pip install flask-mysqldb 若报错可以安装pip install pymsql
- 设置数据库的配置信息
<协议mysql+pymsql>://<用户名>:<密码>@
如果安装的是mysqld,协议使用mysql;如果安装的是pymysql,协议使用mysql+pymysql
- 创建ORM对象SQLALchemy,关联app
- 定义模型类
- *** 作(方法)
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 设置数据库信息
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:123456@127.0.0.1:3306/pytest"
# 设置数据库的追踪数据变化,并压制警告信息
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
#创建SQLAlchemy对象
db = SQLAlchemy(app)
# 定义模型类 角色模型
class Role(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True, nullable=False)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True, nullable=False)
# 外键
role_id = db.Column(db.Integer, db.ForeignKey(Role.id))
@app.route('/')
def hello_world():
return "hello world"
if __name__ == '__main__':
db.create_all() # 将继承自db.Model全部新增
#db.drop_all() 会将继承自db.Model的表全部删掉
#db.session.add(obj) 添加数据,提交回话后才会插入到数据库
#db.session.delete(obj) 删除数据,提交回话后才会更新数据库
#db.session.commit() 提交会话
#db.session.rollback() 回滚
# 添加多条
#us9 = User(name='li',email='li@163.com',password='4526342',role_id=ro2.id)
#us10 = User(name='sun',email='sun@163.com',password='235523',role_id=ro2.id)
#db.session.add_all([us9,us10]) 添加的是一个列表
#db.session.commit()
app.run(debug=True)
执行成功后,数据库会新增两个表,role表和name表,若没有指定表名称,默认是类名的小写,在类中设置__tablename__=="表名"即可
User.query.all() #查询所有用户数据
User.query.count() #查询有多少个用户
User.query.filter_by(name='wang').all() # 精确查询,通过name查询
User.query.first() #查询第1个用户
#查询id为4的用户
User.query.filter_by(id=4).first()
User.query.get(4)
User.query.filter(id==4).first() # filter用于模糊查询
#查询名字结尾字符为g的所有数据[开始/包含]
User.query.filter(User.name.endswith('g')).all()
User.query.filter(User.name.startswith('g')).all() # 以g开头的
User.query.filter(User.name.contains('g')).all() # 包含g
#查询名字不等于wang的所有数据
User.query.filter(User.name != 'wang').all()
#查询名字和邮箱都以 li 开头的所有数据
User.query.filter(User.name.startswith('li'),User.email.startswith('li'))
#查询password是 `123456` 或者 `email` 以 `itheima.com` 结尾的所有数据
from sqlalchemy import or_
User.query.filter(or_(User.password=='123456', User.email.endswith('itheima.com'))).all()
#查询id为 [1, 3, 5, 7, 9] 的用户列表
from sqlalchemy import in_
User.query.filter_by(User.id.in_([1, 3, 5, 7, 9])).all()
# 查询name为liu的角色数据
user = User.query.filter_by(name="liu").first()
role = Role.query.filter(Role.id == user.role_id).first()
# 查询所有用户数据,并以邮箱排序
User.query.order_by(User.email).all() #默认升序
User.query.order_by(User.email.desc()).all() #降序返回
#每页3个,查询第2页的数据
paginate = User.query.paginate(2, 3, False) # False 有错误不输出
paginate.pages # 返回页数
paginate.items # 显示第二页的所有数据
#查询数据后删除
user = User.query.first()
db.session.delete(user)
db.session.commit()
#更新数据
user = User.query.first()
user.name = 'dong'
db.session.commit()
17、backref 反向引用
数据库查询 *** 作:
- 如果知道了用户对象,能不能快速查询出该用户所扮演的角色。例如:user.role
- 如果知道了角色对象,能不能快速查询出哪些用户扮演了该角色。例如:role.user
使用relationship关系属性,设置backref反向引用,一般建立在一方,外键在多方
一对多:A表中的一条数据对应B表中的一条数据,B表中的一条数据对应A表中的多条数据,此时A与B是多对一的关系
In [1]: from test_query import *
In [2]: user = User.query.filter(User.name=='liu').first()
In [3]: user.role
Out[3]:
In [2]: admin = Role.query.filter(Role.name=='admin').first()
In [3]: admin
Out[3]:
In [4]: admin.users
Out[4]:
[,
,
,
]
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)