Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

时间:2022-12-08 18:03:39

1.理解ORM

  • ORM是MTV模型里面的Model模型
  • ORM(Object Relational Mapping),对象关系映射
  • 举例:学生选课

Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

学生和课程这两个实体,一个学生可以选择多门课程,一个课程可以被多名学生选择。这两个实体是多对多的关系,学生选课对应的数据库表

Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

为什么要学习ORM

ORM的重要特性

  • 面向对象的编程思想,方便扩充
  • 少写(几乎不写)SQL,提升开发效率
  • 支持多种类型的数据库,方便切换
  • ORM技术成熟,能解决绝大部分问题

 

2.环境安装

2.1.Flask-sqlalchemy介绍及安装

  • PIP安装: pip install -U Flask-SQLAlchemy 
  • 源码安装: python setup.py install 
  • 使用国内镜像安装: pip install -U -i https://mirrors.aliyun.com/pypi/simple flask-sqlalchemy 

常见安装报错:ERROR: Could not install packages due to an OSError:

Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

解决方案:在pip install 后面加上 --user即可

Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

 

备注:如果是第一次安装flask-sqlalchemy,还需要安装它数据库的依赖mysqlclient。 pip install mysqlclient 

安装mysqlclient常见报错: error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": https://visualstudio.microsoft.com/downloads/

Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

 解决方案1:https://blog.csdn.net/alicee_2012/article/details/122726986

解决方案2:https://blog.csdn.net/weixin_42403632/article/details/117087559(我的报错是通过这个解决的)

 安装成功????Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

 

2.2.Flask-sqlalchemy配置

Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

3.ORM的CURD操作

3.1.设计数据库模型并创建表

 

数据库模型设计

  • 1)绑定到Flask对象: db=SQLAlchemy(app) 
  • 2)ORM模型创建:
    class User(db.Model):
        id=db.Column(db.Integer,primary_key=True)
    View Code
  • 3)指定表的名称: __tablename__='weibo_user' 
  •  

    创建和删除表

    • 1)手动创建数据库
    • 2)创建表: >>> db.create_all(bind='db1') #bind='db1'可以不传,当存在需要对多个数据库创建表时,需要添加对应的数据库对象。只有一个库时,不用加 
    • 3)删除表: >>> db.drop_all() 

     

    实例验证:设计数据库模型,创建/删除表

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

    创建指定名称的表

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

    3.2.数据库模型设计

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

     

    数据库的表肯定不止一张,同时数据表之间都会有一些关联关系,该如何实现?

    • 通过db.ForeignKey()进行外键关联
    • 通过db.relationship()进行反向引用

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

     1 from flask import Flask, render_template
     2 from flask_sqlalchemy import SQLAlchemy
     3 
     4 app = Flask(__name__)
     5 # 配置数据库的连接参数
     6 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:*****@*******/test_flask'
     7 
     8 db = SQLAlchemy(app)
     9 
    10 
    11 class User(db.Model):   #User为模型名称,即类名为模型名称
    12     """ 用户的基础信息 """
    13     __tablename__ = 'weibo_user'
    14     id = db.Column(db.Integer, primary_key=True)
    15     username = db.Column(db.String(64), nullable=False)
    16     password = db.Column(db.String(256), nullable=False)
    17     birth_date = db.Column(db.Date, nullable=True)
    18     age = db.Column(db.Integer, default=0)
    19 
    20 class UserAddress(db.Model):
    21     """ 用户的地址 """
    22     __tablename__ = 'weibo_user_addr'
    23     id = db.Column(db.Integer, primary_key=True)
    24     addr = db.Column(db.String(256), nullable=False)
    25     user_id = db.Column(db.Integer, db.ForeignKey('weibo_user.id'), nullable=False)   #使用db.ForeignKey()进行外键关联
    26     user = db.relationship('User', backref=db.backref('address', lazy=True))      #这一行代码不会在weibo_user_addr这张表里面增加一列,它的作用就是为了方便我们操作模型的时候去访问去查询
    27     # 使用db.relationship()进行反向引用。反向关联谁呢,关联User模型;建立一个反向引用backref=db.backref(),反向引用给谁呢,给address这个名字自己定义,lazy=True就是我们查询到我们用户对象的时候,不直接把他下面所有的地址列表给他查出来,当我们去访问的时候,访问下面地址列表的时候再给他查出来
    28 
    29 '''
    30 接着上面代码举个例子进一步解释说明反向引用:
    31 UserAddress里面有个反向引用,引用的谁呢,引用的User
    32 
    33 场景一:
    34 user = User()   #得到某一个用户张三,想知道张三下面所有得地址列表怎么办?
    35 user.address    #通过user.address就可以获取到到UserAddress这个模型了,就可以找到张三下面得所有地址列表,即地址表内容
    36 
    37 场景二:
    38 假设我们查到了某一个地址,也就是UserAddress模型对应数据库的内容
    39 addr = UserAddress()   #根据地址如何去查用户表的信息呢?
    40 addr.user              #通过addr.user 就得到了User模型的对象,也就是user表对象
    41 '''
    42 
    43 
    44 
    45 @app.route('/')
    46 def mine():
    47     """  首页 """
    48     return render_template('index.html')

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

     

    3.3.使用ORM插入、修改、删除数据

    继续上面代码和用户表、地址表阐述

     

    新增/修改数据

    • 构造ORM模型对象: user = User('admin','admin@example.com') 。在模型类User里面传递一些参数:用户名、密码、用户id等等即user表数据内容,构造一个user对象
    • 添加到db.session,session可以理解为一个会话(备注:session里面可添加多个对象): db.session.add(user) ,可以多次调用add传递多个对象
    • 提交到数据库: db.session.commit ,通过commit就完成了在用户表里面添加一条用户记录

     

    新增数据实例:

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

    修改数据实例:

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

     

    物理删除数据:数据记录在表中直接删掉

    • 通过query.filter_by()查询ORM模型对象: user=User.query.filter_by(username='王五').first() ,通过query.filter_by找到User模型中用户叫王五的数据,first取第一条
    • 添加到db.session,注意这个地方是delete不是add: db.session.delete(user) 
    • 提交变更到数据库: db.session.commit

     

    物理删除数据实例:

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

     

    逻辑删除:相当于软删除,在表中添加一个状态位,比如isvalid字段,用于标记该记录是否删除(0:删除,1:未删除),其实表中数据记录还在的。

     

    3.4.使用ORM进行数据查询与展示

    继续上面代码和用户表、地址表阐述

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

    ORM查询

    ORM查询返回的是一个结果集,可以把它看成list。注意:当模型没有使用__tablename__命名表名,那么表名就是模型名即类的名字。

     

    筛选/获取ORM返回结果集:

    • 查询模型(表)所有数据query.all(): User.query.all() 
    • 按条件查询
      • query.filter_by(): User.query.filter_by(username='张三') 
      • query.filter(): User.query.filter(User.nickname.endswith('')).all() 
      • 可以使用filter()进行一些复杂的查询,:如nickname.endswith() 表中nickname字段是什么结尾的、上面all()是将查询出来的结果全部返回。

     

    对ORM返回结果进行操作:

    • 排序query.order_by(): User.query.order_by(User.username) 
    • 查询TOP10的数据 query.limit(): User.query.limit(10).all() 

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

     

    返回单个ORM对象即查询结果只有一条数据

    • 根据主键(primary_key)值查询: User.query.get(1) 
    • 获取第一条记录first(): User.query.first() 

     

    同时还有一些常用的视图快捷函数:

    • 返回的数据有则返回,无则返回404
      • first()  vs  first_or_404()
      • get()   vs  get_or_404()

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

    •  多表关联查询
      • 方式一:db.session.query(User).join(Address)
      • 方式二:User.query.join(Address)
    • 分页(offset/limit)
      • 方式一:.offset(offset)
      • 方式二:.limit(limit)
      • offset和limit使用方法和在mysql中使用一致
    • 分页(paginate):query对象提供的paginate函数进行分页。 .paginate(page=2,per_page=4) #page当前在第几页,per_page每一页多少条,返回的是一个Pagination的对象 。返回的Pagination对象拥有的属性和函数如下????
      •  has_prev/has_next :是否有上一页/下一页
      •  items :当前页的数据列表
      •  prev_num/next_num :上一页/下一页的页码
      •  total :总记录数
      •  pages :总页数

     

    paginate实例练习:

    1)准备数据

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

    2)分页: list_user.paginate(page2,per_page=4) 

    3)在模板中实现分页操作

     1 '''***app.py***'''
     2 
     3 from flask import Flask, render_template
     4 from flask_sqlalchemy import SQLAlchemy
     5 
     6 app = Flask(__name__)
     7 # 配置数据库的连接参数
     8 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:**@******/test_flask'
     9 db = SQLAlchemy(app)
    10 
    11 
    12 class User(db.Model):
    13     __tablename__ = 'weibo_user'
    14     id = db.Column(db.Integer, primary_key=True)
    15     username = db.Column(db.String(64), nullable=False)
    16     password = db.Column(db.String(256), nullable=False)
    17     birth_date = db.Column(db.Date, nullable=True)
    18     age = db.Column(db.Integer, default=0)
    19 
    20 
    21 class UserAddress(db.Model):
    22     """ 用户的地址 """
    23     __tablename__ = 'weibo_user_addr'
    24     id = db.Column(db.Integer, primary_key=True)
    25     addr = db.Column(db.String(256), nullable=False)
    26     user_id = db.Column(db.Integer, db.ForeignKey('weibo_user.id'), nullable=False)
    27     user = db.relationship('User', backref=db.backref('address', lazy=True))
    28 
    29 
    30 @app.route('/')
    31 def mine():
    32     """  首页 """
    33     return render_template('index.html')
    34 
    35 
    36 @app.route('/user/<int:page>/')
    37 def list_user(page):
    38     """ 用户分页 """
    39     per_page = 10 # 每一页的数据大小
    40     # 1. 查询用户信息
    41     user_ls = User.query
    42     # 2. 准备分页的数据
    43     user_page_data = user_ls.paginate(page, per_page=per_page)
    44     return render_template('list_user.html', user_page_data=user_page_data)
     1 <!--  ***list_user.html***   -->
     2 
     3 <!DOCTYPE html>
     4 <html lang="en">
     5 <head>
     6     <meta charset="UTF-8">
     7     <title>用户分页操作</title>
     8 </head>
     9 <body>
    10 <h3>总共有{{ user_page_data.total }}用户,当前在第{{ user_page_data.page }}页用户, 总共{{ user_page_data.pages }}页</h3>
    11 <p>
    12     用户列表:
    13 
    14 <ul>
    15     {% for user in user_page_data.items %}
    16     <li>{{ user.username }} - {{ user.password }}</li>
    17     {% endfor %}
    18 </ul>
    19 {% if user_page_data.has_prev %}
    20 <a href="{{ url_for('list_user', page=user_page_data.prev_num) }}">上一页</a>
    21 {%  endif %}
    22 {% if user_page_data.has_next %}
    23 <a href="{{ url_for('list_user', page=user_page_data.next_num) }}">下一页</a>
    24 {% endif %}
    25 </p>
    26 </body>
    27 </html>

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用

    思考:

    通过本篇ORM学习,实现了可以将模型数据通过视图传递给模板进行展示。那么模板html如何通过视图对模型中的数据进行增删改查?详见下一篇笔记:Flask表单的实现

    Python全栈工程师之从网页搭建入门到Flask全栈项目实战(5) - Flask中的ORM使用