5.Flask基本使用
5.1 虚拟环境的创建
1.创建flask的虚拟环境
mkvirtualenv --python=/usr/bin/python3 flask200x
2.查看虚拟环境
pip freeze
pip list
3.虚拟环境迁移
pip freeze > requirements.txt
迁出
pip install -r requirements.txt
迁入
5.2 Flask项目的创建
1.安装
国外源 pip install flask
国内源 pip install flask -i https://pypi.douban.com/simple
2.创建项目
代码结构
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "Hello"
app.run()
3.启动服务器 python 文件名字.py
默认端口号 5000 只允许本机连接
5.3 启动服务器参数修改
run方法中添加参数
在启动的时候可以添加参数 在run()中
debug
是否开启调试模式,开启后修改过python代码自动重启
如果修改的是html/js/css 那么不会自动重启
host
主机,默认是127.0.0.1 指定为0.0.0.0代表本机ip
port
指定服务器端口号
threaded
是否开启多线程
6. flask-script-(命令行参数)
1.安装
pip install flask-script
作用
启动命令行参数
2.初始化
修改 文件.py为manager.py
manager = Manager(app=app)
修改 文件.run()为manager.run()
3.运行
python manager.py runserver -p xxx -h xxxx -d -r
参数
- p 端口 port
- h 主机 host
- d 调试模式 debug
- r 重启(重新加载) reload(restart)
7. 视图函数返回值
(1)index返回字符串
@app.route('/index/')
def index():
return 'index'
(2)模板first.html
@app.route('/first/')
def hello():
return render_template("test.html")
静态文件css
注意
6. Flask基础结构
App
templates
模板
static
静态资源
views
视图函数
models
模型
坑点
执行过程中manager.py和其他的文件的路径问题
第二个坑--封装__init__文件--
7. flask-blueprint-(蓝图)
蓝图
1. 宏伟蓝图(宏观规划)
2. 蓝图也是一种规划,主要用来规划urls(路由)
3. 蓝图基本使用
- 安装
- pip install flask-blueprint
- 在视图文件中 初始化蓝图 blue = Blueprint('first',__name__)
注意导包 from flask import Blueprint
- 在manager中 调用蓝图进行路由注册 app.register_blueprint(blueprint=blue)
8. Flask路由参数
8.1 概念
路由中带参数的请求,从客户端或者浏览器发过来的请求带参数。
基本使用:
@blue.route('/getstudents//')
def getstudents(id):
return '学生%s'+id
8.2 基础语法
基础语法
书写的converter可以省略,默认类型就是string
converter
(1)string
接收的时候也是str, 匹配到 / 的时候是匹配结束
@blue.route('/getperson//')
def getperson(name):
print(name)
print(type(name))
return name
(2)path
接收的时候也是str, / 只会当作字符串中的一个字符处理
@blue.route('/getperson1//')
def getperson1(name):
print(name)
print(type(name))
return name
(3)int
@blue.route('/makemoney//')
def makemoney(money):
print(type(money))
return '1'
(4)float
@blue.route('/makemoneyfloat//')
def makemoney(money):
print(type(money))
return '1'
(5)uuid(uuid 类型,一种格式)
@blue.route(('/getuu/'))
def getuu():
uu = uuid.uuid4()
print(uu)
return str(uu)
------------------------------------
@blue.route('/getuuid//')
def getuuid(uuid):
print(uuid)
print(type(uuid))
return '2'
(6)any(已提供选项的任意一个 而不能写参数外的内容 注意的是/)
@blue.route('/getany//')
def getany(p):
return '1'
9.postman
请求方式
postman
模拟请求工具
方法参数中添加methods=['GET','POST']
1. 默认支持GET,HEAD,OPTIONS
2. 如果想支持某一请求方式,需要自己手动指定
3. 在route方法中,使用methods=["GET","POST","PUT","DELETE"]
10.反向解析
(1)概念:
获取请求资源路径
(2)语法格式:
url_for(蓝图的名字.方法名字)
(3)使用:
@blue.route("/hehe/", methods=["GET","POST","PUT"])
def hehe():
return "呵呵哒"
@blue.route("/gethehe/")
def get_hehe():
p = url_for("first.hehe")
return p
作业:
1.执行请求login,跳转到login.html,该页面中有一个文本框,在文本框中输入红浪漫晶哥,然后点击提交,跳转到weilcome.html,该页面中显示欢迎光临尊敬的vip中p晶哥,光临红浪漫,男宾一位,拖鞋手牌拿好,楼上二楼左转。
Day02
学习目标
- request
- response
- 异常
- 会话
- cookie
- session
- 模板
- 模型
学习课程
1.request
(1)request是一个内置对象
内置对象:不需要创建就可以直接使用的对象
(2)属性
1.method (请求方法) **
2.base_url (去掉get参数的url)
3.host_url (只有主机和端口号的url)
4.url (完整的请求地址) **
5.remote_addr (请求的客户端地址) **
6.request.args.get('name')
args **
- args
- get请求参数的包装,args是一个ImmutableMultiDict对象,类字典结构对象
- 数据存储也是key-value
- 外层是大列表,列表中的元素是元组,元组中左边是key,右边是value
- ImmutableMultiDict([('age', '18'), ('age', '19'), ('name', 'zs')])
注意: 一般情况下 get请求方式都是在浏览器的地址栏上显示
eg:http://www.baiduc.com/s?name=zs&age=18
获取get请求方式的参数的方式:request.args.get('name')
7.request.form.get('name')
form **
- form
- 存储结构和args一致
- 默认是接收post参数
- 还可以接收 PUT,PATCH参数
注意:eg:
2 Response
(1)返回字符串
如果只有字符串,就是返回内容,数据
还有第二个返回,放的是状态码
@blue.route('/response/')
def get_response():
return '德玛西亚',404
(2)render_template
渲染模板
将模板变成字符串
@blue.route('/rendertemplate/')
def render_temp():
resp = render_template('Response.html')
print(resp)
print(type(resp))
return rese,500
(3)make_response
Response对象
返回内容
状态码
@blue.route('/makeresponse/')
def make_resp():
resp = make_response('xxxxxxxx
',502)
print(resp)
print(type(resp))
return rese
(4)redirect
重定向
@blue.route('/redirect/')
def make_redir():
return redirect('/makeresponse/')
反向解析 url_for
@blue.route('/redirect/')
def make_redir():
return redirect(url_for('first.make_resp'))
(5)Response()
@blue.route('/testresponse4/')
def testresponse4():
res = Response('呵呵')
print(type(res))
return res
3.异常
abort
直接抛出 显示错误状态码 终止程序运行
abort(404)
eg:
@blue.route('/makeabort/')
def make_abort():
abort(404)
return '天还行'
捕获
@blue.errorhandler()
- 异常捕获
- 可以根据状态或 Exception进行捕获
- 函数中要包含一个参数,参数用来接收异常信息
eg:
@blue.errorhandler(502)
def handler502(exception):
return '不能让你看到状态码'
4.会话技术
1.请求过程Request开始,到Response结束
2.连接都是短连接
3.延长交互的生命周期
4.将关键数据记录下来
5.Cookie是保存在浏览器端/客户端的状态管理技术
6.Session是服务器端的状态管理技术
(1)cookie
Cookie
1.客户端会话技术
2.所有数据存储在客户端
3.以key-value进行数据存储层
4.服务器不做任何存储
5.特性
(1)支持过期时间
max_age 毫秒
expries 具体日期
(2)根据域名进行cookie存储
(3)不能跨网站(域名)
(4)不能跨浏览器
(5)自动携带本网站的所有cookie
6.cookie是服务器操作客户端的数据
7.通过Response进行操作
cookie登陆使用
设置cookie response.set_cookie('username',username)
获取cookie username = request.cookies.get('username','游客')
删除cookie response.delete_cookie('username')
(2)session
Session
1.服务端会话技术
2.所有数据存储在服务器中
3.默认存在服务器的内存中
- django默认做了数据持久化(存在了数据库中)
4.存储结构也是key-value形势,键值对
【注】单纯的使用session是会报错的,需要使用在__init__方法中配置app.config['SECRET_KEY']=‘110’
session登陆使用
设置 session['username'] = username
获取 session.get('username')
删除
resp.delete_cookie('session')
session.pop('username')
(3)cookie和session总结
(1)cookie: 客户端浏览器的缓存;session: 服务端服务器的缓存
(2)cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session
(3)session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie
可以考虑将登陆信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中
(4)session持久化问题
-
持久化简介
1.django中对session做了持久化,存储在数据库中 2.flask中没有对默认session进行任何处理 - flask-session 可以实现session的数据持久化 - 可以持久化到各种位置,更推荐使用redis - 缓存在磁盘上的时候,管理磁盘文件使用lru, 最近最少使用原则
持久化实现方案
1.pip install flask-session
在国内源安装
pip install flask-sessin -i https://pipy.douban.com/simple
2.初始化Session对象
(1)持久化的位置
配置init中app.config['SESSION_TYPE'] = 'redis'
(2)初始化
创建session的对象有2种方式 分别是以下两种
1 Session(app=app)
2 se = Session() se.init_app(app = app)
(3)安装redis
pip install redis
设置了默认开机启动,如果没有设置,那么需要将redis服务开启
(4)需要配置SECRET_KEY='110'
注意:flask把session的key存储在客户端的cookie中,通过这个key可以从flask的内存中获取 用户的session信息,出于安全性考虑,使用secret_key进行加密处理。所以需要先设置secret_key的值。
(5)其他配置--视情况而定
app.config['SESSION_KEY_PREFIX']='flask'
特殊说明:
查看redis内容
redis-cli
keys *
get key
session生存时间31天
ttl session
flask的session的生存时间是31天,django的session生存时间是14天
5.Template
- 简介:
(1)MVC中的View,MTV中的Template
(2)主要用来做数据展示的
(3)模板处理过程分为2个阶段
1 加载
2 渲染
(4)jinja2模板引擎
1.本质上是html
2.支持特定的模板语法
3.flask作者开发的 一个现代化设计和友好的python模板语言 模仿的django的模板引擎
4.优点
速度快,被广泛使用
HTML设计和后端Python分离
减少Python复杂度
非常灵活,快速和安全
提供了控制,继承等高级功能
-
模板语法
-
基本语法
模板语言动态生成的html {{ var }} 变量的接收 从views传递过来的数据 前面定义出来的数据
-
结构标签
(1)block 首次出现挖坑操作 第二次出现填坑操作 第N次出现,填坑操作,会覆盖前面填的坑 不想被覆盖,需要添加 {{ super() }} (2)extends 继承 (3)include 包含,将一个指定的模板包含进来
-
宏定义(macro)
(1)无参 {% macro say()%} 你饿了吗??? {% endmacro %} (2)有参 {% macro createUser(name,age)%} 欢迎{{ name }} 心理没点数吗 你都{{ age }}大了 {% endmacro %} (3)外文件中的宏定义调用需要导入也可以include {% macro getUser(name)%} 欢迎光临红浪漫{{ name }},拖鞋手牌拿好,楼上2楼左转,男宾一位 {% endmacro %} {% from ‘html文件’ import yyy %} {{ getUser('action') }}
-
循环控制
for for .. in loop 循环信息 索引 index 第一个 first 最后一个last if if else elif
-
过滤器
语法格式:{{ var|xxx|yyy|zzz }} 没有数量限制 lower upper trim reverse striptags 渲染之前将值中的标签去掉 safe 标签生效 eg: {% for c in config %}
- {{ loop.index0 }}:{{ loop.index}}:{{ c|lower|reverse }}
{% endfor %}
-
6.models
- 简介
1.数据交互的封装
2.Flask默认并没有提供任何数据库操作的API
Flask中可以自己的选择数据,用原生语句实现功能
原生SQL缺点:
(1)代码利用率低,条件复杂代码语句越过长,有很多相似语句
(2)一些SQL是在业务逻辑中拼出来的,修改需要了解业务逻辑
直接写SQL容易忽视SQL问题
也可以选择ORM
SQLAlchemy
MongoEngine
将对象的操作转换为原生SQL
优点
(1)易用性,可以有效减少重复SQL
(2)性能损耗少
(3)设计灵活,可以轻松实现复杂查询
(4)移植性好
3.Flask中并没有提供默认ORM
ORM 对象关系映射
通过操作对象,实现对数据的操作
- sqlalchemy
flask-sqlalchemy
使用步骤:1.pip install flask-sqlalchemy
2.创建SQLALCHEMY对象
①:db=SQLAlchemy(app=app)
②:db=SQLAlchemy() 上面这句话一般会放到models中 因为需要db来调 用属性 db.init_app(app=app)
3.config中配置 SQLALCHEMY_DATABASE_URI
数据库 + 驱动 :// 用户:密码@ 主机:端口/数据库
dialect+driver://username:password@host:port/database
eg:mysql+pymysql://root:1234@localhost:3306/flask1905
4.执行
views中db.create_all()
注意:有坑
(1)primary-key
添加主键
(2)SQLALCHEMY_TRACK_MODIFICATIONS
app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS’]=False
使用:
(1)定义模型
继承Sqlalchemy对象中的model
eg:
class User(db.Model):
id = db.Column(db.Integer,primary_key=True,autoincrement=True)l
name = db.Column(db.String(32))
age = db.Column(db.Integer)
(2)创建
db.create_all()
(3)删除
db.drop_all()
(4)修改表名
__tablename__ = "Worker"
(5)数据操作
添加
db.session.add(对象)
db.session.commit()
查询
模型.query.all()
Models
学习目标
ORM
flask-migrate
DML
DQL
数据定义
模型关系
学习课程
1. ORM
1.1 简介
对象关系映射(Object Relational Mapping,简称ORM。ORM是通过使用描述对象和数据库之间映射,将程序中的对象自动持久化到关系数据库中。让我们从O/R开始。字母O起源于"对象"(Object),而R则来自于"关系"(Relational)。几乎所有的程序里面,都存在对象和关系数据库。在业务逻辑层和用户界面层中,我们是面向对象的。当对象信息发生变化的时候,我们需要把对象的信息保存在关系数据库中。
当你开发一个应用程序的时候(不使用O/R Mapping),你可能会写不少数据访问层的代码,用来从数据库保存,删除,读取对象信息,等等。
[图片上传失败...(image-4f20ee-1586850584104)]
简单说,ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping) 的缩写。
ORM 把数据库映射成对象。
[图片上传失败...(image-77ec9-1586850584104)]
2. flask-migrate(模型迁移)
使用步骤
(1)安装
pip install flask-migrate
(2)初始化
1.创建migrate对象
需要将app 和 db初始化
migrate = Migrate()
migrate.init_app(app=app, db=db)
2.懒加载初始化
结合flask-script使用
在manage上添加command (MigrateCommand)
manager.add_command("db", MigrateCommand)
(3)python manager.py db xxx
1.init 生成migrations文件夹
2.migrate 生成迁移文件
不能生成有2种情况
(1)模型定义完成从未调用
(2)数据库已经有模型记录
3.upgrade 升级 执行迁移文件
4.downgrade 降级
扩展:
创建用户文件
python manager.py db migrate --message ‘创建用户’
3. DML
3.1 增 删 改
1.增
创建对象
(1)添加一个对象
db.session.add()
eg:
@blue.route("/addperson/")
def add_person():
p = Person()
p.p_name = "小明"
p.p_age = 15
db.session.add(p)
db.session.commit()
return "添加成功"
(2)添加多个对象
db.session.add_all()
eg:
@blue.route("/addpersons/")
def app_persons():
persons = []
for i in range(5):
p = Person()
p.p_name = "猴子请来的救兵%d" % random.randrange(100)
p.p_age = random.randrange(70)
persons.append(p)
db.session.add_all(persons)
db.session.commit()
return "添加成功"
2.删除
db.session.delete(对象)
基于查询
3.修改
db.session.add(对象)
基于查询
3.2 查
1.获取单个数据
(1)get
主键值
获取不到不会抛错
person = Person.query.get(3)
db.session.delete(person)
db.session.commit()
(2)first
person = Person.query.first()
2.获取结果集
(1)xxx.query.all
persons = Person.query.all()
(2)xxx.query.filter_by
persons = Person.query.filter_by(p_age=15)
(3)xxx.query.filter
persons = Person.query.filter(Person.p_age < 18)
persons = Person.query.filter(Person.p_age.__le__(15))
persons = Person.query.filter(Person.p_name.startswith("小"))
persons = Person.query.filter(Person.p_name.endswith("1"))
persons = Person.query.filter(Person.p_name.contains("1"))
persons = Person.query.filter(Person.p_age.in_([15, 11]))
3.数据筛选
(1)order_by
persons = Person.query.order_by("-p_age")
(2)limit
persons = Person.query.limit(5)
(3)offset
persons = Person.query.offset(5).order_by("-id")
(4)offset和limit不区分顺序,offset先生效
persons = Person.query.order_by("-id").limit(5).offset(5)
persons = Person.query.order_by("-id").limit(5)
persons = Person.query.order_by("-id").offset(17).limit(5)
(5)order_by 需要先调用执行
persons = Person.query.order_by("-id").offset(17).limit(5)
4.pagination
(1)简介:分页器
需要想要的页码
每一页显示多少数据
(2)原生:
persons = Person.query.offset((page_num - 1) * page_per).limit(page_per)
(3)封装:
参数(page,page_per,False(是否抛异常)
persons = Person.query.paginate(page_num, page_per, False).items
5.逻辑运算
(1)与
and_ filter(and_(条件))
huochelist = kaihuoche.query.filter(and_(kaihuoche.id == 1,kaihuoche.name == 'lc'))
(2)或
or_ filter(or_(条件))
huochelist = kaihuoche.query.filter(or_(kaihuoche.id == 1,kaihuoche.name =='lc'))
(3)非
not_ filter(not_(条件)) 注意条件只能有一个
huochelist = kaihuoche.query.filter(not_(kaihuoche.id == 1))
(4)in
huochelist = kaihuoche.query.filter(kaihuoche.id.in_([1,2,4]))
4. 数据定义
(1)字段类型
Integer
String
Date
Boolean
(2)约束
primary_key (主键)
autoincrement (主键自增长)
unique (唯一)
default (默认)
index (索引)
not null (非空)
ForeignKey (外键)
用来约束级联数据
db.Column( db.Integer, db.ForeignKey(xxx.id) )
使用relationship实现级联数据获取
声明级联数据
backref="表名"
lazy=True
5. 模型关系
5.1 一对多
(1)模型定义
class Parent(db.Model):
id=db.Column(db.Integer,primary_key=True,autoincrement=True)
name=db.Column(db.String(30),unique=True)
children=db.relationship("Child",backref="parent",lazy=True)
def __init__(self):
name=self.name
class Child(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30), unique=True)
parent_id = db.Column(db.Integer, db.ForeignKey('parent.id'))
def __init__(self):
name = self.name
(2)参数介绍:
1.relationship函数
sqlalchemy对关系之间提供的一种便利的调用方式,关联不同的表;
2.backref参数
对关系提供反向引用的声明,在Address类上声明新属性的简单方法,之后可以在my_address.person来获取这个地址的person;
3.lazy参数
(1)'select'(默认值)
SQLAlchemy 会在使用一个标准 select 语句时一次性加载数据;
(2)'joined'
让 SQLAlchemy 当父级使用 JOIN 语句是,在相同的查询中加载关系;
(3)'subquery'
类似 'joined' ,但是 SQLAlchemy 会使用子查询;
(4)'dynamic':
SQLAlchemy 会返回一个查询对象,在加载这些条目时才进行加载数据,大批量数据查询处理时推荐使用。
4.ForeignKey参数
代表一种关联字段,将两张表进行关联的方式,表示一个person的外键,设定上必须要能在父表中找到对应的id值
(3)模型的应用
添加
eg:@blue.route('/add/')
def add():
p = Parent()
p.name = '张三'
c = Child()
c.name = '张四'
c1 = Child()
c1.name = '王五'
p.children = [c,c1]
db.session.add(p)
db.session.commit()
return 'add success'
查
eg:
主查从 --》 Parent--》Child
@blue.route('/getChild/')
def getChild():
clist = Child.query.filter(Parent.id == 1)
for c in clist:
print(c.name)
return 'welcome to red remonce'
从查主
@blue.route('/getParent/')
def getParent():
p = Parent.query.filter(Child.id == 2)
print(type(p))
print(p[0].name)
return '开洗'
52 一对一
一对一需要设置relationship中的uselist=Flase,其他数据库操作一样。
5.3 多对多
(1)模型定义
class User(db.Model):
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
name = db.Column(db.String(32))
age = db.Column(db.Integer,default=18)
class Movie(db.Model):
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
name = db.Column(db.String(32))
class Collection(db.Model):
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
u_id = db.Column(db.Integer,db.ForeignKey(User.id))
m_id = db.Column(db.Integer,db.ForeignKey(Movie.id))
(2)应用场景
购物车添加
@blue.route('/getcollection/')
def getcollection():
u_id = int(request.args.get('u_id'))
m_id = int(request.args.get('m_id'))
c = Collection.query.filter(Collection.u_id == u_id).filter_by(m_id = m_id)
if c.count() > 0:
print(c.first().u_id,c.first().m_id)
# print(c)
# print(type(c))
# print('i am if')
return '已经添加到了购物车中'
else:
c1 = Collection()
c1.u_id = u_id
c1.m_id = m_id
db.session.add(c1)
db.session.commit()
return 'ok'