Flask----关系映射
-
一对多关系
-
什么是一对多
A表中的一条数据可以关联到B表中的多条数据
B表中的多条数据 -
一对多在数据库中的实现
靠 主外键 的关系来实现一对多
“一”表中有主键
在“多”表中增加外键,表示对“一”表的引用 -
在SQLAlchemy中的实现
- 原则:
在"多"实体类中增加对"一"实体类的引用
在"一"实体类中增加"关联属性"以及"反向引用关系属性"
-
在"多"实体类中
增加一个属性/列,要引用到"一" 表/类的主键属性名/外键列名 = db.Column( db.type, db.ForeignKey('主键表名.主键列') )
#增加一个外键列-course_id,引用自Course类(course表)的主键id
class Teacher(db.Model): __tablename__ = "teacher" id = db.Column(db.Integer, primary_key=True) tname = db.Column(db.String(30),nullable=False) tage = db.Column(db.Integer) #增加一个外键列-course_id,引用自Course类(course表)的主键id course_id = db.Column( db.Integer, db.ForeignKey('course.id') )
-
在"一"实体类中
增加关联属性和反向引用关系属性
目的:为了创建类(对象)与类(对象)之间的关联关系-
关联属性
在"一"实体类中,要增加一个《属性》来获取"多"的实体类对象们 -
反向引用关系属性
在"一"实体类中做操作最终加到了"多"实体类中
语法:在"一"实体类中增加: 属性名 = db.relationship( '多的实体类名', backref = '定义反向引用关系属性名' lazy = 'dynamic' )
#增加对Teacher的关联属性和反向引用关系属性
class Course(db.Model): __tablename__ = "course" id = db.Column(db.Integer, primary_key=True) cname = db.Column(db.String(30)) #增加对Teacher的关联属性和反向引用关系属性 teachers = db.relationship( "Teacher", backref = "course", lazy = 'dynamic' )
以上操作执行完毕后,对数据库和程序的影响:
- 对数据库的影响
在teacher中增加一个列----course_id(外键)
表示的就是对course的主键id的一个引用 - 对 程序的影响
- 在Teacher类中,会增加一个属性 —course_id
表示的是该Teacher对象关联的课程id - 在Course类中,会增加一个属性–teachers
表示的是该Course对象所关联对应的所有的Teacher们 - 在Teacher类中,会增加一个属性–course
表示的是该Teacher对象所关联对应的一门Course的对象
- 在Teacher类中,会增加一个属性 —course_id
@app.route('/12-regtea') def regtea(): #1.通过teacher对象的course_id属性插入关联的数据 teaQi = Teacher() teaQi.tname = "齐老师" teaQi.tage = 30 teaQi.course_id = 1 db.session.add(teaQi) # 2.通过teacher对象的course属性插入关联数据 # 2.1查询出'python高级'对象 course = Course.query.filter_by(cname='python高级').first() # 2.2声明tea对象,并关联查询出的course对象 tea = Teacher() tea.tname = "吕泽Maria" tea.tage = 31 tea.course = course #底层是将course.id给了tea.course_id属性 return "插入成功"
新增一个路由,添加老师属性,并添加到数据库
@app.route('/13-otm',methods=["GET","POST"]) def otm(): if request.method == "GET": # 1.查询出course中的所有数据x` courses = Course.query.all() # 2.渲染模板 return render_template("13-otm.html",courses = courses) else: # 1.接收前端提交过来的参数 tname = request.form['tname'] tage = request.form['tage'] course_id = request.form['cid'] # 2.创建对象并赋值 tea = Teacher() tea.tname = tname tea.tage = tage tea.course_id = course_id # 3.插入数据进数据库 db.session.add(tea) return "注册成功了"
HTML页面----13.otm.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/13-otm" method="post"> <p>姓名:<input type="text" name="tname"></p> <p>年龄:<input type="number" name="tage"></p> <p>课程:<select name="cid"> {% for cour in courses %}} <option value="{{cour.id}}">{{cour.cname}}</option> {% endfor %} </select></p> <button>注册</button> </form> </body> </html>
- 对数据库的影响
-
- 原则:
-
关联数据的查询
-
通过"一"的对象找关联的"多"的对象们
示例:当得到一门Course的信息后,如何获取对应的所有的Teacher们
解决:通过 关联属性 来表示对应的类型数据的查询对象
course=Course.query.fitler_by(id=1).first()
#查询出course对象所对应的所有的teachen们
teachers = course.teachers.all() -
通过"多"的对象找关联的"一"的对象
解决:通过反向引用关系属性
示例:查找 祁老师 所教授的课程
tea = Teacher.query.filter_by(tname=‘祁老师’)
cour = tea.course@app.route('/14-otm-query') def otm_query(): # 1.通过course对象找到对应的teacher # 1.1查询id为1的course的信息 cour = Course.query.filter_by(id=1).first() print("课程:",cour.cname) # 1.2获取当前course所对应的teacher们 teachers = cour.teachers.all() for tea in teachers: print("姓名:%s,年龄:%s"%(tea.tname,tea.tage)) # 2.查找齐老师所教授的课程 tea = Teacher.query.filter_by(tname='齐老师').first() cour = tea.course print("老师姓名:",tea.tname) print("课程:",cour.cname) return "关联数据查询陈宫"
作业:在HTML中切换响应的课程,显示所对应的老师,首次访问显示全部老师
@app.route("/15-otm-exer") def otm_exer(): # 1.查询出所有的课程 courses = Course.query.all() # 获取前端提交锅里的cid参数值,如果没有当0处理 # 如果cid的值是0的话则查询所有的老师信息 # 如果cid的值是非0的话 则按照cid的值查询老师信息 # 2.查询出所有的老师 cid = int(request.args.get('cid', 0)) if cid == 0: teachers = Teacher.query.all() else: # 方案1:通过cid到Teacher试题中查询数据 # teachers = Teacher.query.filter_by(course_id=cid).all() # 方案2:通过cid获取课程信息,在通过课程找到对应的老师们 course = Course.query.filter_by(id=cid).first() teachers = course.teachers.all() # 3.将课程和老师们渲染到模板中 return render_template('15-otm-exer.html', params=locals())
HTML页面 ----- 15-otm-exer.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="/static/jquery-1.11.3.js"></script> <script> $(function () { $('#selCour').change(function () { location.href="/15-otm-exer?cid="+this.value; }) }) </script> </head> <body> <select id="selCour"> <option value="0">所有</option> {% for cour in params.courses %} <option value="{{cour.id}}" {% if cour.id == params.cid%} selected {% endif %} >{{cour.cname}}</option> {% endfor %} </select> <table width="400" border="1"> <tr> <th>姓名</th> <th>年龄</th> <th>所教课程</th> </tr> {% for tea in params.teachers %} <tr> <td>{{tea.tname}}</td> <td>{{tea.tage}}</td> <td>{{tea.course.cname}}</td> </tr> {% endfor %} </table> </body> </html>
-
-
-
一对一关系
- 在关联的两张表中的任意一张表中:
- 增加外键,并引用另一张表的主键
- 并且要增加唯一约束
-
在ORM中实现
-
在任意一个实体类中增加外键以及唯一约束
外键列名 = db.Column( db.TYPE, db.ForeignKey("主表.主键") unique = True )
demo:
创建Teacher与Wife之间的一对一关系Wife中增加外键列 - teacher_id#增加一个属性,teacher_id,表示对Teacher类的主键的引用,并且实施唯一的约束
class Wife(db.Model): id = db.Column(db.Integer,primary_key=True) wname = db.Column(db.String(30)) isActive = db.Column(db.Boolean, default=True) # 增加一个列birthday birthday = db.Column(db.Date) # 增加一个属性,teacher_id,表示对Teacher类的主键的引用,并且实施唯一的约束 teacher_id = db.Column(db.Integer, db.ForeignKey('teacher.id'), unique=True)
-
-
关联属性 和 反向引用关系属性
在关联的两个类中的另一个类中增加:属性名 = db.relationship( "关联的实体类名" backref = "反向应用关系属性名" uselist = False )
uselist:设置为False,表示关联属性是一个标量而并非一个列表
#增加一个关联属性,表示引用Wife的信息,
class Teacher(db.Model): __tablename__ = "teacher" id = db.Column(db.Integer, primary_key=True) tname = db.Column(db.String(30), nullable=False) tage = db.Column(db.Integer) # 增加一个外键列-course_id,引用自Course类(course表)的主键id course_id = db.Column( db.Integer, db.ForeignKey('course.id') ) # 增加一个关联属性,表示引用Wife的信息, # 关联属性:在teacher中要增加哪个属性用于表示Wife的引用 # 反向引用关系属性:在teacher中设置但要增加到Wife中,表示在Wife中增加那个属性表示对Teacher的引用 wife = db.relationship("Wife", backref="teacher", uselist=False)
添加到wife的两种方案以及查询代码
@app.route("/16-oto") def oto_views(): # 1.方案1:通过wife对象中的teacher_id属性表示要引用的teacher的主键 # wife = Wife() # wife.wname = "如花" # wife.teacher_id = 1 # db.session.add(wife) # 2.方案2:通过wife对象中的teacher属性表示要引用teacher对象 # teacher = Teacher.query.filter_by(id=2).first() # wife = Wife() # wife.wname = "小泽夫人" # wife.teacher = teacher # db.session.add(wife) # 3.查询 每一名wife所对应的teacher的信息 wifes = Wife.query.all() for w in wifes: print(f"夫人姓名:{w.wname},老师姓名:{w.teacher.tname}") # 4.查询 每一名teacher所对应的wife的信息 teachers = Teacher.query.all() for tea in teachers: print(f"老师姓名:{tea.tname}") if tea.wife: print(f"夫人姓名:{tea.wife.wname}") print("-----------------------") return "成功了了"
- 在关联的两张表中的任意一张表中:
-
多对多关系
- 什么是对对多
A表中的一条数据能关联到B表中的多条数据上
B表中的一条数据能关联到A表中的多条数据上 - 在数据库中的实现
依靠第三张关联表的方式来实现 - 在ORM中实现
-
创建第三张表(类)
-
关联属性 和 反向引用关系属性
# 常见Student_Course类,映射到student_course # 表示Student与Course之间的多对多的第三张关联表 class StudentCourse(db.Model): __tablename__ = "student_course" id = db.Column(db.Integer,primary_key=True) # 外键student_id,用用子student表的主键id student_id = db.Column(db.Integer,db.ForeignKey('student.id')) # 外键student_id,用用子student表的主键id course_id = db.Column(db.Integer,db.ForeignKey('course.id'))
在关联的两个类中的任意一个类中增加:
属性名 = db.relationship( "另一个类名", secondary = "第三张关联表表名", lazy = "dynamic", backref = db.backref( "反向引用关系属性名", lazy = "dynamic", ) )
-
- 什么是对对多
cookie
- cookies
- 什么是cookies
cookie 是一种数据存储的手段
将一段文本保存在浏览器上的一种手段,并可以长时间保存 - 使用场合
1. 记住密码
2. 记录用户的操作习惯,行为,关键词 - cookie特点
1. 长时间保存
2. 明文
3. 可以通过浏览器修改
4. 有浏览器之分
5. cookie有网站之分 - Flask中使用cookies
- 保存数据到cookies中
通过响应对象将数据保存进cookies中-
响应对象的构建
- 重定向就是响应对象
resp = redirect("/xxx") - 通过make_response()将字符串构建成响应对象
from flask import make_response
resp = make_response("" 或 render_template())
- 重定向就是响应对象
-
保存cookie的语法
响应对象.set_cookie(key,value,max_age) key:保存到cookie中的数据的名称 value:保存到cookie中的数据的值 max_age:最大的存活时长,以秒为单位
from flask import Flask, make_response, request, render_template, session app = Flask(__name__) app.config['SECRET_KEY'] = "lkjhgfdsakjhgfd" #写什么都行 @app.route('/01-setcookie') def setcookie(): # 保存用户名和密码进cookies # 通过make_response resp = make_response("保存cookies成功") resp.set_cookie("uname", "Qtx", 60 * 60) resp.set_cookie("upwd", "lzmaria", ) return resp
-
获取cookies的值
通过 request.cookies 获取所有的cookies值
request.cookies 的类型是 dict@app.route('/02-getcookie') def getcookie(): if "uname" in request.cookies: uname = request.cookies['uname'] print(uname) upwd = request.cookies.get('upwd', '密码为空') print("密码" + upwd) return "获取成功"
-
删除cookie的值
响应对象.delete_cookie(‘key’)@app.route('/03-delcookie') def delcookie(): resp = make_response("删除cookie成功") if 'uname' in request.cookies: resp.delete_cookie('uname') return resp
-
- 保存数据到cookies中
- 什么是cookies
设置一个页面,当账号密码都为admin时,显示登陆成功,否则登陆失败
@app.route('/04-login', methods=["GET", "POST"])
def login():
if request.method == "GET":
# 判断Cookie中是否有uname
if 'uname' in request.cookies:
# 判断unam的有效性是否为admin
uname = request.cookies['uname']
if uname == 'admin':
return f"欢迎{uname}回来,<a href='/05-logout'>退出</a>"
return render_template('04-login.html')
else:
# 接收用户名和密码判断是否正确
uname = request.form['uname']
upwd = request.form['upwd']
if uname == 'admin' and upwd == 'admin':
# 登录成功
resp = make_response(f"欢迎{uname}登录,<a href='/05-logout'>退出</a>")
# 判断是否记住密码
if 'isSaved' in request.form:
resp.set_cookie("uname", uname, 60 * 60 * 24)
return resp
else:
return "<script>alert('登录失败');location.href='/04-login';</script>"
#退出
@app.route('/05-logout')
def logout():
if 'uname' in request.cookies:
resp = make_response("退出成功")
resp.delete_cookie('uname')
return resp
return "退出了"
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/04-login" method="post">
<p>
登录名称:<input type="text" name="uname">
</p>
<p>登录密码:<input type="password" name="upwd"></p>
<p><input type="checkbox" name="isSaved">记住密码</p>
<p><button>登录</button></p>
</form>
</body>
</html>
session
- 什么是session
session – 会话
当浏览器打开时。跟一个服务器交互的过程就是一次会话
session的目的:为了保存会话中所涉及到的一些信息 - session在Flask中的实现
- 配置: SECRET_KEY
app.config[‘SECRET_KEY’] = “什么都能写” - 使用session
from flask import session-
向session中保存数据
session[‘key’] = value@app.route('/06-setsession') def setsession(): session['uname'] = 'lvzemaria' return "保存数据进session成功"
-
从session中获取数据
value = session[‘key’]
value = session.get(‘key’)@app.route('/07-getsession') def getsession(): if 'uname' in session: uname = session['uname'] print("uname:"+uname) else: print("session没有uname的值") return "获取成功"
-
删除session中的数据
del session[‘key’]@app.route('/08-delsession') def delsession(): if 'uname' in session: del session['uname'] return "删除成功" return "删除失败"
-
- session PK cookie
- cookie
- 保存在客户端[位置]
- 明文可以修改,安全性较低-----安全性
- 长时间保存 ------保存时长
- session
- 保存在服务器上 位置
- 安全性高 安全
- 临时性的存储时长
- cookie
- 配置: SECRET_KEY