falsk
flask: 是一个轻量级的框架, 只提供了基本的路由路径处理工具( Werkzeug) , 和页面渲染功能( jinja2) , 如果要实现其他额外的功能需要安装扩展包.
里面提供了两个核心内容: Werkzeug + jinja2
Werkzeug: 负责处理请求相关内容
jinja2: 负责渲染页面的.
额外扩展: 比如邮件发送Flask_Mail, Flask_Sqlalchemy, 等等.
知识点-1
01.Flask类创建对象的默认参数
print ( app. static_folder)
/ home/ python/ Desktop/ Program/ flask/ static
/ static
templates
02.url_map
返回: 是一个map集合,里面装着地址( 路径) 和视图函数之间的映射关系,例如,
Map( [ < Rule '/static/<filename>' ( GET, HEAD, OPTIONS) -> static> ] )
03.视图函数指定访问方式(methods)
methods设置请求的方式,默认就是GET请求,例如,
@app.route( "/methods" , methods = [ "GET" , "POST" , "PUT" ] )
常见的访问方式: GET,POST,PUT,DELETE,等8种
04.url_for
注意:函数名,要加双引号 ""
@app.route( "/urlfor1" )
def url_for1( ) :
body_02 = url_for( 'url_for2' )
return "url_for1 <a href='%s'>点我</a>" % body_02
@app.route( "/urlfor2" )
def url_for2( ) :
return "url_for2 <a href='%s'>点我</a>" % url_for( 'url_for1' )
05.redirect重定向
格式: redirect( '路由地址' ) , 返回的就是一个响应体对象
场景: 向服务器A请求资源1, 没有这个资源直接跳转到2
特点: 两次请求
注意: 当资源2路由路径里带参数时,需要利用url_for( "函数名" ,参数= xx) ,得到其路由路径
06.jsonify
1 . 设置响应体对象的headers属性
resp = make_response( 'helloworld' )
resp = make_response( render_template( "index.html" ) )
resp. headers[ 'Content-Type' ] = 'application/json'
return resp
2 . 使用flask中提供的方法, jsonify( )
dict1 = {
"name" : "zhangsan" ,
"age" : "13"
}
return jsonify( dict1)
简化写法:
return jsonify( name= 'zhangsan' , age= 13 )
@app. route ( "/" )
def hello_world ( ) :
return jsonify( name= "zs" , age= "18" )
{
"age" : "13" ,
"name" : "zhangsan"
}
07.参数类型
格式: @app. route( '/地址/<参数类型:变量名>' )
常见参数类型:
int 整数
float 小数
path 字符串类型
接收字符串( path) , 默认可以省略
08.自定义类型
1 . 自定义类, 继承自BaseConverter
2 . 编写初始化方法, init方法, 接收两个参数, url_map, regex, 并初始化父类空间和子类空间
3 . 将自定义转换器类, 添加到默认的转换列表中
app. url_map. converters[ key] = 转换器类
自定义转换器方法之to_python方法:
执行时间: 匹配到规则之后, 执行视图函数之前
作用: 用来过滤数据, 还可以做编码转换
from flask import Flask
from werkzeug. routing import BaseConverter
app = Flask( __name__)
class MyRegexConverter ( BaseConverter) :
def __init__ ( self, url_map, regex) :
super ( MyRegexConverter, self) . __init__( url_map)
self. regex = regex
def to_python ( self, value) :
print ( "value = %s" % value)
return int ( value) + 10
app. url_map. converters[ 're' ] = MyRegexConverter
print ( app. url_map. converters)
@app. route ( '/<re("\d{3}"):num>' )
def hello_world ( num) :
print ( "num = %s" % num)
return "the num is %s" % num
@app. route ( '/<re("1[3-9]\d{9}"):mobile>' )
def get_phone_number ( mobile) :
return "the mobile is %s" % mobile
if __name__ == '__main__' :
app. run( debug= True )
09.abort主动抛出异常
场景: 当访问服务器资源的时候, 如果不存在/ 权限不够, 可以直接使用abort抛出异常
@app. errorhandler ( 代号/ 对象) : 可以捕捉异常代号, 返回统一的界面. 装饰方法执行
结束进程
当前端口号为5000 时,
查看端口占用情况: lsof - i: 5000
杀掉进程: kill 进程编号(pid)
from flask import Flask
from flask import abort
app = Flask( __name__)
@app. route ( '/game/<int:age>' )
def game ( age) :
if age < 18 :
abort( 404 )
return "play game"
@app. errorhandler ( 404 )
def not_found_page ( e) :
print ( e)
return "找不到页面了"
@app. errorhandler ( Exception)
def error ( e) :
return "报错了"
if __name__ == '__main__' :
app. run( debug= True )
10.debug里的参数
在使用app.run()的时候,可以传递参数
参数有: host: IP地址默认是127.0.0.1
参数有: port: Port端口默认是5000
参数有: debug: 默认是False
如果设置成True,会有很多好处
app.run(host='127.0.0.1', port=5001, debug=True)
11.app运行加载参数
app. run( ) 运行的时候有些配置信息需要加载, 有三种方式可以加载内容
方式一: 可以从类中加载
app. config. from_object( 类名称)
方式二: 可以从配置文件
app. config. from_pyfile( 文件名称)
方式三: 可以从环境变量加载, 依赖文件, 不常用
app. config. from_envvar( '环境名称key' )
12.request请求
request, 是Werkzeug提供好的请求对象, 里面封装了请求相关的所有信息, 比如: 请求地址, 请求参数, 请求方式, 等等
request. url: 请求地址
request. method: 请求方式
request. args: 请求参数, 并且是问好后面拼接的内容, www. baidu. com?name= zhangsan& age= 13
request. args为字典,取值用get来
request. data 非表单和ajax提交,接收到的格式为json,需要转换
json_data = request. data
dcit_data = json. loads( json_data)
request. json 等于上面的两句话,得到的是字典格式的数据
request. form 去表单的数据,也是字典的格式
例如,print ( request. args[ 'name' ] )
print ( request. args. get( 'name' ) )
知识点-2
01.请求勾子
在处理第一个请求前执行,例如
@app. before_first_request
def before_first_request ( ) :
print ( "before_first_request" )
在每次请求前执行
如果在某修饰的函数中返回了一个响应,视图函数将不再被调用
如果没有抛出错误,在每次请求后执行
接受一个参数:视图函数作出的响应, response
在此函数中可以对响应值在返回之前做最后一步修改处理
需要将参数中的响应在此参数中进行返回, return
在每次请求后执行
接受一个参数:错误信息,如果有相关错误抛出
from flask import Flask, request
app = Flask( __name__)
@app. before_first_request
def before_first_request ( ) :
print ( "before_first_request" )
@app. before_request
def before_request ( ) :
token = request. args. get( "token" )
if token != "3" :
return "你是坏蛋,不能访问"
print ( "before_request" )
@app. after_request
def after_request ( resp) :
print ( "after_request" )
resp. headers[ "Content-Type" ] = "application.json"
return resp
@app. teardown_request
def teardown_request ( e) :
print ( e)
print ( "teardown_request" )
@app. route ( '/' )
def hello_world ( ) :
print ( "hello world" )
return "hello world"
if __name__ == '__main__' :
app. run( debug= True )
02.响应内容response
a. 直接返回, 响应体
return "hello"
b. 返回, 响应体 + 状态码
return "hello" , "666 BIGERROR"
BIGERROR对666 进行的说明
c. 返回, 响应体 + 状态码 + 响应头( 字典格式)
return "hello" , "666 BIGERROR" , { "name" : "banzhang" , "Content-Type" : "application/json" }
创建响应体, 设置内容再返回
resp = make_response( 'hello' )
resp. status = '888 XIAGAO'
resp. headers[ "content-Type" ] = "application/json"
return resp
03.状态保持
状态保持, 通过cookie和session来进行状态保持
用来保存浏览器和服务器交互信息的内容, 由服务器设置, 存储在浏览器
设置方式:
resp = make_response( "hello world" )
resp. set_cookie( key, value, max_age)
max_age: 表示cookie的有效时间
获取方式:
value = request. cookies. get( key)
注意点: 如果不设置cookie的有效期, 默认就是一次浏览器会话结束,即关闭浏览器
from flask import Flask, make_response, request
app = Flask( __name__)
@app. route ( '/set_cookie/<path:content>' )
def set_cookie ( content) :
resp = make_response( "set_cookie" )
resp. set_cookie( "name" , content)
resp. set_cookie( "age" , '13' , 10 )
return resp
@app. route ( '/get_cookie' )
def get_cookie ( ) :
name = request. cookies. get( "name" )
age = request. cookies. get( "age" )
return "name is %s, age is %s" % ( name, age)
pass
if __name__ == '__main__' :
app. run( debug= True )
也是用来做状态保持, 比如: 登陆状态, 适合存储敏感信息, 比如, 卡号, 密码等, 由服务器设置, 存储在服务器, 需要依赖于cookie( sessionID存储cookie)
设置session:
session[ key] = value
获取session:
value = session. get( key)
注意点:
1 . 由于session空间的钥匙( sessionID) , 存储在浏览器cookie, 所以需要加密存储
2 . 加密存储需要设置秘钥SECRET_KEY
from flask import Flask
from flask import session
app = Flask( __name__)
app. config[ 'SECRET_KEY' ] = 'DFSAFSDFSDF'
@app. route ( '/set_session/<path:name>' )
def set_session ( name) :
session[ "name" ] = name
return "set_session"
@app. route ( '/get_session' )
def get_session ( ) :
name = session. get( "name" )
return "get_session,name is %s" % name
if __name__ == '__main__' :
app. run( debug= True )
04.上下文(g)
request: 相当于一个容器, 或者是一个线程局部变量. request是和每一个请求相关的.
session: 相当于一个容器, 存储在服务器内部的. 线程局部变量.
current_app: 相当于是app的一个代理对象, 主要使用在模块开发中.
g: g. name 可以用在请求勾子里的 before_request, li
from flask import Flask, current_app, g
app = Flask( __name__)
@app. before_request
def before_request ( ) :
g. name = "zhangsan"
@app. route ( '/' )
def hello_world ( ) :
print ( current_app. url_map)
name = g. name
return "hello world ---> {}" . format ( name)
pass
if __name__ == '__main__' :
print ( app. url_map)
app. run( debug= True )
05.扩展包flask_script
作用:
1 . 用来通过命令的方式去启动程序, 并且可以指定端口和ip,
2 . 并且配合flask_migrate可以做数据库迁移.
使用流程:
1 . 安装, pip install flask_script
2 . 导入包中类
from flask_scirpt import Manager
3 . 使用Manager管理app
manager = Manager( app)
4 . 启动程序
注意点:
1 . 配置右键运行, 右上角编辑configration添加runserver
2 . 配置debug模式, 在管理之前配置
3 . 运行程序, python xxx. py runserver - h ip地址 - p 端口
from flask import Flask
from flask_script import Manager
app = Flask( __name__)
class Config ( object ) :
DEBUG = True
app. config. from_object( Config)
manager = Manager( app)
@app. route ( '/' )
def hello_world ( ) :
return "hello world"
pass
if __name__ == '__main__' :
manager. run( )
python manage. py runserver
python manage. py runserver - h 127.0 .0 .1 - p 8090
python manage. py runserver - - help
python manage. py runserver - h 127.0 .0 .1 - p 8080 - d - - threaded
06.template模板
flask中提供了两个核心功能, werkzueg + jinja2
jinja2就是用来做模板( html文件) 渲染, 使用的是render_template( '页面' , key= value, key2= value2) 渲染
取变量的值:
{ { 变量名 } }
分支语句if :
{ % if 条件A % }
语句1 ;
{ % elif 条件B % }
语句2 ;
{ % else % }
语句3 ;
{ % endif % }
循环结构for :
{ % for 变量名 in 容器 % }
{ % endfor % }
返回的值为:
return render_template( "file01render_template.html" )
07.filter过滤器
safe:禁用转义, 让html标签生效
< p> { { '<h1>hello</h1>' | safe } } < / p>
capitalize:把变量值的首字母转成大写,其余字母转小写, 中文没有大小写
lower:把值转成小写
upper:把值转成大写
title:把值中的每个单词的首字母都转成大写
reverse:字符串反转
format :格式化输出,例如:
< p> { { '%s is %d' | format ( 'age' , 17 ) } } < / p>
striptags:渲染之前把值中所有的HTML标签都删掉, 和safe相反,例如,
< p> { { '<h1>hello</h1>' | striptags } } < / p>
first:取第一个元素,例如,
< p> { { [ 1 , 2 , 3 , 4 , 5 , 6 ] | first } } < / p>
last:取最后一个元素
length:获取列表长度
sum :列表求和,例如,
< p> { { [ 1 , 2 , 3 , 4 , 5 , 6 ] | sum } } < / p>
sort:列表排序
08.自定义过滤器
def test ( ) :
pass
app. add_template_filter( 函数名称, '过滤器名称' )
例如:
def get_jishu ( list1) :
new_list = [ ]
for item in list1:
if item % 2 != 0 :
new_list. append( item)
return new_list
app. add_template_filter( get_jishu, "jishu" )
@app. template_filter ( '过滤器名称' )
def test ( )
pass
例如:
@app. template_filter ( "oushu" )
def get_oushu ( list2) :
new_list1 = [ ]
for item in list2:
if item % 2 == 0 :
new_list1. append( item)
return new_list1
loop. index0,编号0 开始
loop. index,编号1 开始
09.模板复用
宏( macro) : 实际上相当于python中函数, 提前定义好一段功能, 需要的时候调用
定义格式:
{ % macro 宏名( 参数) % }
{ % endmacro % }
例如:
{ % macro test( name1, age1) % }
< label for = "" > { { name1 } } < / label>
< input type = "text" value= "123" > < br>
< label for = "" > { { age1 } } < / label>
< input type = "text" value= "456" >
{ % endmacro % }
{ { test( "姓名:" , "age:" ) } }
在当前文件调用:
{ { 宏名( 参数) } }
其他文件定义的, 调用
{ % import '宏文件名' as 别名 % }
{ { 别名. 宏名( 参数) } }
{ % import "file06import.html" as test1 % }
{ { test1. test( "姓名:" , "年龄:" ) } }
场景: 对于表单结构固定, 但是内容不固定, 可以使用
继承: 共性抽取, 代码复用, 并且可以扩展子类自己的内容, 更加灵活
格式: { % extends '文件名' % }
父文件名定义, 一般切割很多块:
{ % block 模块名称 % }
{ % endblock % }
{ % block title % }
< h1> 全场大甩卖< / h1>
{ % endblock % }
{ % block content % }
< h3> 只要998< / h3>
{ % endblock % }
{ % block bottom % }
< h4> thankyou< / h4>
{ % endblock % }
{ % extends "file08father.html" % }
{ % block content % }
{
{ { super ( ) } }
< h3> 不要钱了< / h3>
{ % endblock % }
格式: { % include '文件名' % }
格式: { % include '文件名' ignore missing % } 如果文件名不存在不会报错
{ % include "file07children.html" ignore missing% }
该文件里的效果和file07里的效果一样
10.jinja2里特殊变量(flash)
jinja2中给提供了一些特殊的变量, 不需要传递就可以使用
常用的有:
config: app的配置对象
request: 请求对象
url_for( ) : 方法, 通过函数名称找路径
get_flashed_messages( ) : 消耗消息队列中的数据, 也就是存储在也就是存储在flash里面的数据
存数据:flash( "数据" )
一次性把数据全部取出来:get_flashed_messages( ) , 得到的是一个列表
注意点:
1 , 使用flash, 存储数据的时候需要, 设置SECRET_KEY
2 . 因为flash, 依赖session
app. config[ "SECRET_KEY" ] = "fjkdjfkdjfkdjfkdf"
知识点-3
01.传统表单
传统表单组成:
是由大量的html标签组成的, 唯一繁琐的地方在于一旦表单写好之后,
如果要进行更改和增加验证功能比较麻烦.
案例: 注册案例
注意点:
如果是表单提交, 使用request. form获取
拓展:all ( [ 参数1 ,参数2 ] ) 表示如果里面有一个参数为空的话,就为False ,例如,
if not all ( [ username, password, repassword] )
"""
传统表单组成:
是由大量的html标签组成的,唯一繁琐的地方在于一旦表单写好之后,
如果要进行更改和增加验证功能比较麻烦.
案例: 注册案例
注意点:
如果是表单提交,使用request.form获取
""" ""
from flask import Flask, render_template, request
app = Flask( __name__)
@app. route ( '/' )
def show_page ( ) :
return render_template( 'file01normal_form.html' )
@app. route ( '/register' , methods= [ 'POST' ] )
def register ( ) :
username = request. form. get( 'username' )
password = request. form. get( 'password' )
repassword = request. form. get( 'repassword' )
if not all ( [ username, password, repassword] ) :
return "参数不全,注册失败"
if password != repassword:
return "两次密码不一致,注册失败"
return "注册成功"
if __name__ == '__main__' :
app. run( debug= True )
{
把该表单的内容发到/ register,即页面跳到/ register
< form action= "/register" method= "post" >
{
< label> 用户名: < / label> < input type = "text" name= "username" > < br>
< label> 密码: < / label> < input type = "password" name= "password" > < br>
< label> 确认密码: < / label> < input type = "password" name= "repassword" > < br>
< input type = "submit" value= "注册" >
< / form>
< / body>
< / html>
02.flask_wtf表单
1 . 提供了验证函数
2 . 提供了csrf校验机制
1 . 安装扩展
pip install flask_wtf
from flask_wtf import FlaskForm
from wtforms import 字段
from wtforms. validates import 验证函数
2 . 自定义类继承自FlaskForm, 编写字段和验证函数
3 . 创建表单, 进行渲染
1 . 由于flask_wtf表单提供了csrf验证机制, csrf_token的生成需要依赖于SECRET_KEY进行加密
2 . 如果是wtf表单, 获取数据方式, form. username. data
3. flask_wtf表单默认开启了csrf校验. 关闭方式:
4 . 通过validate_on_submit( ) , 会校验: 'POST' , 'PUT' , 'PATCH' , 'DELETE' 请求方式校验, 还会校验验证函数和csrf_token
2.1.WTForms支持的HTML标准字段
字段对象 说明 StringField 文本字段 TextAreaField 多行文本字段 PasswordField 密码文本字段 HiddenField 隐藏文件字段 DateField 文本字段,值为 datetime.date 文本格式 DateTimeField 文本字段,值为 datetime.datetime 文本格式 IntegerField 文本字段,值为整数 DecimalField 文本字段,值为decimal.Decimal FloatField 文本字段,值为浮点数 BooleanField 复选框,值为True 和 False RadioField 一组单选框 SelectField 下拉列表 SelectMutipleField 下拉列表,可选择多个值 FileField 文件上传字段 SubmitField 表单提交按钮 FormField 把表单作为字段嵌入另一个表单 FieldList 一组指定类型的字段
2.2WTForms常用验证函数
验证函数 说明 DataRequired 确保字段中有数据 EqualTo 比较两个字段的值,常用于比较两次密码输入 Length 验证输入的字符串长度 NumberRange 验证输入的值在数字范围内 URL 验证URL AnyOf 验证输入值在可选列表中 NoneOf 验证输入值不在可选列表中
使用 Flask-WTF 需要配置参数 SECRET_KEY。
CSRF_ENABLED是为了CSRF(跨站请求伪造)保护。 SECRET_KEY用来生成加密令牌,当CSRF激活的时候,该设置会根据设置的密匙生成加密令牌。
2.3flask_wtf的使用
"""
flask_wtf表单,属于flask的扩展包,通过类名称渲染表单,然后字段的形式渲染标签.
好处:
1.提供了验证函数
2.提供了csrf校验机制
1.安装扩展
pip install flask_wtf
from flask_wtf import FlaskForm
from wtforms import 字段
from wtforms.validates import 验证函数
2.自定义类继承自FlaskForm,编写字段和验证函数
3.创建表单,进行渲染
""" ""
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms. validators import DataRequired, EqualTo
app = Flask( __name__)
app. config[ 'SECRET_KEY' ] = "fjdkfjkdkjfkd"
class MyForm ( FlaskForm) :
username = StringField( label= '用户名' , validators= [ DataRequired( '用户不能为空' ) ] )
password = PasswordField( label= '密码' , validators= [ DataRequired( '密码不能为空' ) ] )
repassword = PasswordField( label= '确认密码' , validators= [ DataRequired( '确认密码不能为空' ) ,
EqualTo( 'password' , '两次密码不一致' ) ] )
submit = SubmitField( '提交' )
@app. route ( '/' )
def hello_world ( ) :
form = MyForm( )
return render_template( 'file02wtf_form.html' , form= form)
@app. route ( '/register' , methods= [ 'POST' ] )
def register ( ) :
form = MyForm( )
if form. validate_on_submit( ) :
print ( form. username. data)
print ( form. password. data)
print ( form. repassword. data)
return "注册成功"
return "注册失败"
if __name__ == '__main__' :
app. run( debug= True )
< form action= "/register" method= "post" >
{
{ { form. csrf_token } }
{ { form. username. label } }
{ { form. username } } < br>
{ { form. password. label } }
{ { form. password } } < br>
{ { form. repassword. label } }
{ { form. repassword } } < br>
{ { form. submit } }
< / form>
03.ORM模型
ORM模型类表示的是扩展包flask_sqlahchemy中的SQLALchemy类
orm: 将模型类中的类名, 属性, 对象, 映射成数据库里面的表名, 字段, 一行一行数据.
1 . 安装, 导入包
pip install flask_sqlalchemy
pip install flask_mysqldb
pip install pymysql
from flask_sqlalchemy import SQLAlchemy
2 . 设置配置信息, 比如: 账号, 密码地址等信息
3 . 创建SQLAlchemy类对象, 关联app
4 . 编写模型类, 继承db. Model
5 . 操作数据库使用方法而不是sql语句了.
添加单个对象: db. session. add( obj)
添加多个对象: db. session. add_all( [ obj1, obj2] )
提交数据库: db. session. commit( )
创建表: db. create_all( ) ,创建继承db. Model的表
删除所有表: db. drop_all( ) 删除继承db. Model的表
删除: db. session. delete( obj)
回滚: db. session. rollback( )
1 . 如果安装的数据库驱动是flask_mysqldb 格式:
mysql: // < 用户名> : < 密码> @< IP地址> : < 端口> / < 数据库名>
2 . 如果安装的数据库驱动是pymysql 格式
mysql+ pymysql: // < 用户名> : < 密码> @< IP地址> : < 端口> / < 数据库名>
3 . 默认生成的表名称是类名称小写, 如果需要手动指定表名, 编写__tablename__ = '表名'
使用orm的优点
不需要写sql语句, 提高开发效率
缺点:
由于不是通过sql语句直接操作数据库, 所以有性能损失.
3.1数据库的操作
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask( __name__)
app. config[ "SQLALCHEMY_DATABASE_URI" ] = "mysql+pymysql://root:mysql@127.0.0.1:3306/demo"
app. config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False
db = SQLAlchemy( app)
class Role ( db. Model) :
__tablename__ = "roles"
id = db. Column( db. Integer, primary_key= True )
name = db. Column( db. String( 64 ) , unique= True )
users = db. relationship( 'User' , backhref= 'role' , lazy= 'dynamic)
def __repr__ ( self) :
return "<Role:%s>" % self. name
class User ( db. Model) :
__tablename__ = "users"
id = db. Column( db. Integer, primary_key= True )
name = db. Column( db. String( 64 ) , unique= True )
role_id = db. Column( db. Integer, db. ForeignKey( Role. id ) )
def __repr__ ( self) :
return "<User:%s,%s>" % ( self. id , self. name)
@app. route ( '/' )
def hello_world ( ) :
return "helloworld"
if __name__ == '__main__' :
db. drop_all( )
db. create_all( )
app. run( debug= True )
3.2常用的SQLAlchemy字段类型
db.Column(db.类型,)
类型名 python中类型 说明 Integer int 普通整数,一般是32位 SmallInteger int 取值范围小的整数,一般是16位 BigInteger int或long 不限制精度的整数 Float float 浮点数 Numeric decimal.Decimal 普通整数,一般是32位 String str 变长字符串 Text str 变长字符串,对较长或不限长度的字符串做了优化 Unicode unicode 变长Unicode字符串 UnicodeText unicode 变长Unicode字符串,对较长或不限长度的字符串做了优化 Boolean bool 布尔值 Date datetime.date 时间 Time datetime.datetime 日期和时间 LargeBinary str 二进制文件
3.3常用的SQLAlchemy列选项
选项名 说明 primary_key 如果为True,代表表的主键 unique 如果为True,代表这列不允许出现重复的值 index 如果为True,为这列创建索引,提高查询效率 nullable 如果为True,允许有空值,如果为False,不允许有空值 default 为这列定义默认值
3.4常用的SQLAlchemy关系选项
db.relationship(‘类名’,backref=‘关系名’)
选项名 说明 backref 在关系的另一模型中添加反向引用 primary join 明确指定两个模型之间使用的联结条件 uselist 如果为False,不使用列表,而使用标量值 order_by 指定关系中记录的排序方式 secondary 指定多对多关系中关系表的名字 secondary join 在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件
04.数据库的查询操作
User. query. all ( ) 查看所有的结果
User. query. get( 6 ) ,6 为id
User. query. filter_by( id = 4 ) . all ( ) ,得出的结果为列表
User. query. filter ( User. id == 4 ) . first( ) ,里面是条件, 得出来是单个对象
User. query. filter ( User. name. endswith( 'g' ) ) . all ( )
User. query. filter_by( id = 4 ) . first( ) ,该过滤器用的很少
过滤器一般后面要有方法
User. query. filter ( User. name != "wang" ) . all ( )
User. query. filter ( User. name. endswith( "li" ) , User. name. startswith( "li" ) ) . all ( )
from sqlalchemy import or_
User. query. filter ( or_( User. password== "123456" , User. email. endswith( 'itheima.com' ) ) ) . all ( ) ,
User. query. filter ( User. id . in_( [ 1 , 3 , 5 , 7 , 9 ] ) ) . all ( )
User. query. filter ( User. name. contains( 'g' ) ) . all ( )
User. query. count( )
User. query. order_by( User. email. desc( ) ) . all ( )
默认为asc( ) 升序,desc( ) 降序
paginate = User. query. paginate( 2 , 3 , False )
例如,有10 条数据
paginate. pages , 表示总共几页,4 页
paginate. page, 当前页,2
paginate. itmes, 当前页的数据
user1 = User. query. get( 1 )
db. session. delete( user1)
4.1常用的SQLAlchemy查询过滤器
过滤器 说明 filter() 把过滤器添加到原查询上,返回一个新查询 filter_by() 把等值过滤器添加到原查询上,返回一个新查询 limit 使用指定的值限定原查询返回的结果 offset() 偏移原查询返回的结果,返回一个新查询 order_by() 根据指定条件对原查询结果进行排序,返回一个新查询 group_by() 根据指定条件对原查询结果进行分组,返回一个新查询
4.2常用的SQLAlchemy查询执行器
方法 说明 all() 以列表形式返回查询的所有结果 first() 返回查询的第一个结果,如果未查到,返回None first_or_404() 返回查询的第一个结果,如果未查到,返回404 get() 返回指定主键对应的行,如不存在,返回None get_or_404() 返回指定主键对应的行,如不存在,返回404 count() 返回查询结果的数量 paginate() 返回一个Paginate对象,它包含指定范围内的结果
4.3 原生sql语句
@hello_blu. route ( "/db" )
def get_db ( ) :
sql = """SELECT * FROM account
WHERE id = :aid;"""
ret = db. session. execute( sql, { "aid" : 1 } )
ret = ret. fetchall( )
for item in ret:
print ( item)
return "db"
知识点-04
01.多对多
注意点: ( 学生课程表)
1 . 需要在关系属性中添加secondary = 中间表名
2 . 外键写在中间表中
3 . 关系属性的编写依赖于外键, 如果没有外键, 关系属性不能使用
4. lazy: 可以设置为dynamic, 可以动态查询( 用到的时候查询) , 默认是子查询( subquery)
02.数据库迁移
是通过扩展包, flask_migrate和flask_script来实现
操作流程:
1 . 安装, 导入
pip install flask_migrate 提供两个类, Migrate, MigrateCommand
pip install flask_script, 提供了Manager
2 . 创建Manager对象, 关联app
3 . 使用Migrate类, 关联app和db
4 . 添加一条操作命令MigrateCommand
5 . 编写操作语句
1 . 生成迁移文件( 一次就好)
python manage. py db init
2 . 生成迁移脚本( 记录模型类的字段信息)
python manage. py db migrate - m"版本名(注释)"
3 . 更新迁移脚本到数据库( upgrade调用的是迁移脚本中的方法)
python manage. py db upgrade/ downgrade [ version]
4 . 查看所有版本号
python manage. py db history
5 . 查看最新版本号
python manage. py db show
注意点:
降级有风险, 操作需谨慎,(数据丢失)
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
app = Flask( __name__)
app. config[ "SQLALCHEMY_DATABASE_URI" ] = "mysql+pymysql://root:mysql@127.0.0.1:3306/demo"
app. config[ "SQLALCHEMY_TRACK_MODIFICATIONS" ] = False
class Student ( db. Model) :
id = db. Column( db. Integer, primary_key= True )
name = db. Column( db. String( 64 ) )
age = db. Column( db. Integer)
db = SQLAlchemy( app)
manager = Manager( app)
Migrate( app, db)
manager. add_command( 'db' , MigrateCommand)
@app. route ( '/' )
def hello_world ( ) :
return "hello world"
if __name__ == '__main__' :
manager. run( )
03.蓝图
在蓝图包的init里写,1 ,导入蓝图,2 创建蓝图对象
在views里写,3 . 蓝图对象装饰可视函数
在一个模块名a里写,4 . 蓝图注册到app中,导入蓝图包
蓝图: 是flask中专门用来模块化开发的技术, 不需要安装扩展包就可以使用
使用流程:
1 . 导入包
from flask import Blueprint
2 . 创建蓝图对象
3 . 使用蓝图对象, 装饰视图函数
4 . 将蓝图注册到app中
cart_blu = Blueprint( "cart" , __name__, url_prefix= '/cart' , static_folder= 'static' , template_folder= 'templates' )
from flask import Blueprint
cart_blue = Blueprint( 'cart' , __name__)
from cart import views
from cart import cart_blue
@cart_blue. route ( '/goods' )
def goods ( ) :
return 'goods'
@cart_blue. route ( '/list' )
def lists ( ) :
return 'list'
from flask import Flask
from cart import cart_blue
app = Flask( __name__)
app. register_blueprint( cart_blue)
if __name__ == '__main__' :
app. run( )
04.断言assert
assertEqual 如果两个值相等,则pass
assertNotEqual 如果两个值不相等,则pass
assertTrue 判断bool 值为True ,则pass
assertFalse 判断bool 值为False ,则pass
assertIsNone 不存在,则pass
assertIsNotNone 存在,则pass
self. assertIsNotNone( author2, '对象不能为空' )
正常的 assert 布尔表达式,说明
在测试案例中,即在类中抵用
self. assertEqual( 布尔表达式,说明)
断言( assert ) : 一般就用在单元测试, 和框架中.
格式:
assert boolean表达式1 , 语句A
执行流程:
如果表达式1 , 为True , 继续向后执行
如果表达式1 , 为False , 抛出异常, 执行语句A
def div ( num1, num2) :
assert isinstance ( num1, int ) , 'num1必须是整数'
assert isinstance ( num2, int ) , 'num2必须是整数'
return num1 / num2