Flask----关系映射

Flask----关系映射

  1. 一对多关系

    1. 什么是一对多
      A表中的一条数据可以关联到B表中的多条数据
      B表中的多条数据

    2. 一对多在数据库中的实现
      靠 主外键 的关系来实现一对多
      “一”表中有主键
      在“多”表中增加外键,表示对“一”表的引用

    3. 在SQLAlchemy中的实现

      • 原则:
        在"多"实体类中增加对"一"实体类的引用
        在"一"实体类中增加"关联属性"以及"反向引用关系属性"
      1. 在"多"实体类中
        增加一个属性/列,要引用到"一" 表/类的主键

        属性名/外键列名 = 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')
            )
        
      2. 在"一"实体类中
        增加关联属性和反向引用关系属性
        目的:为了创建类(对象)与类(对象)之间的关联关系

        1. 关联属性
          在"一"实体类中,要增加一个《属性》来获取"多"的实体类对象们

        2. 反向引用关系属性
          在"一"实体类中做操作最终加到了"多"实体类中
          语法:

           在"一"实体类中增加:
           	属性名  = 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'
              )
          

          以上操作执行完毕后,对数据库和程序的影响:

          1. 对数据库的影响
            在teacher中增加一个列----course_id(外键)
            表示的就是对course的主键id的一个引用
          2. 对 程序的影响
            1. 在Teacher类中,会增加一个属性 —course_id
              表示的是该Teacher对象关联的课程id
            2. 在Course类中,会增加一个属性–teachers
              表示的是该Course对象所关联对应的所有的Teacher们
            3. 在Teacher类中,会增加一个属性–course
              表示的是该Teacher对象所关联对应的一门Course的对象
          @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>
          
    4. 关联数据的查询

      1. 通过"一"的对象找关联的"多"的对象们
        示例:当得到一门Course的信息后,如何获取对应的所有的Teacher们
        解决:通过 关联属性 来表示对应的类型数据的查询对象
        course=Course.query.fitler_by(id=1).first()
        #查询出course对象所对应的所有的teachen们
        teachers = course.teachers.all()

      2. 通过"多"的对象找关联的"一"的对象
        解决:通过反向引用关系属性
        示例:查找 祁老师 所教授的课程
        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>
        
  2. 一对一关系

    • 在关联的两张表中的任意一张表中:
      1. 增加外键,并引用另一张表的主键
      2. 并且要增加唯一约束
    1. 在ORM中实现

      1. 在任意一个实体类中增加外键以及唯一约束

         外键列名 = 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)
        
    2. 关联属性 和 反向引用关系属性
      在关联的两个类中的另一个类中增加:

       	属性名 = 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 "成功了了"
      
  3. 多对多关系

    1. 什么是对对多
      A表中的一条数据能关联到B表中的多条数据上
      B表中的一条数据能关联到A表中的多条数据上
    2. 在数据库中的实现
      依靠第三张关联表的方式来实现
    3. 在ORM中实现
      1. 创建第三张表(类)

      2. 关联属性 和 反向引用关系属性

        # 常见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

  1. cookies
    1. 什么是cookies
      cookie 是一种数据存储的手段
      将一段文本保存在浏览器上的一种手段,并可以长时间保存
    2. 使用场合
      1. 记住密码
      2. 记录用户的操作习惯,行为,关键词
    3. cookie特点
      1. 长时间保存
      2. 明文
      3. 可以通过浏览器修改
      4. 有浏览器之分
      5. cookie有网站之分
    4. Flask中使用cookies
      1. 保存数据到cookies中
        通过响应对象将数据保存进cookies中
        1. 响应对象的构建

          1. 重定向就是响应对象
            resp = redirect("/xxx")
          2. 通过make_response()将字符串构建成响应对象
            from flask import make_response
            resp = make_response("" 或 render_template())
        2. 保存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
          
        3. 获取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 "获取成功"
          
        4. 删除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
          

设置一个页面,当账号密码都为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

  1. 什么是session
    session – 会话
    当浏览器打开时。跟一个服务器交互的过程就是一次会话
    session的目的:为了保存会话中所涉及到的一些信息
  2. session在Flask中的实现
    1. 配置: SECRET_KEY
      app.config[‘SECRET_KEY’] = “什么都能写”
    2. 使用session
      from flask import session
      1. 向session中保存数据
        session[‘key’] = value

        @app.route('/06-setsession')
        def setsession():
            session['uname'] = 'lvzemaria'
            return "保存数据进session成功"
        
      2. 从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 "获取成功"
        
      3. 删除session中的数据
        del session[‘key’]

        @app.route('/08-delsession')
        def delsession():
            if 'uname' in session:
                del session['uname']
                return "删除成功"
            return "删除失败"
        
    3. session PK cookie
      1. cookie
        1. 保存在客户端[位置]
        2. 明文可以修改,安全性较低-----安全性
        3. 长时间保存 ------保存时长
      2. session
        1. 保存在服务器上 位置
        2. 安全性高 安全
        3. 临时性的存储时长
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值