1.理解ORM

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

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

为什么要学习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:

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

备注:如果是第一次安装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/

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

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

安装成功

2.2.Flask-sqlalchemy配置

3.ORM的CURD操作

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

数据库模型设计

  • 1)绑定到Flask对象: db=SQLAlchemy(app)
  • 2)ORM模型创建:

    1. class User(db.Model):
    2. id=db.Column(db.Integer,primary_key=True)
  • 3)指定表的名称: __tablename__='weibo_user'

创建和删除表

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

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

创建指定名称的表

3.2.数据库模型设计

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

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

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

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就完成了在用户表里面添加一条用户记录

新增数据实例:

修改数据实例:

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

  • 通过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

物理删除数据实例:

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

3.4.使用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()

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

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

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

  • 返回的数据有则返回,无则返回404

    • first()  vs  first_or_404()
    • get()   vs  get_or_404()

  • 多表关联查询

    • 方式一: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)准备数据

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

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

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

思考:

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

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

  1. Python全栈工程师之从网页搭建入门到Flask全栈项目实战(3) - 入门Flask微框架

    1.安装Flask 方式一:使用pip命令安装 pip install flask 方式二:源码安装 python setup.py install 验证 第一个Flask程序 程序解释 参数__na ...

  2. Python全栈工程师之从网页搭建入门到Flask全栈项目实战(1) - ES6标准入门和Flex布局

    1.简述 1.什么是ES6?ES6, 全称 ECMAScript 6.0,是 JavaScript 的下一个版本标准,2015年6月份发版.ES6的主要目的是为了解决 ES5 的先天不足. 2.了解E ...

  3. Web全栈工程师修养

    全栈工程师现在是个很热的话题,如何定义全栈工程师?在著名的问答网站Quora上有人提出了这个问题,其中一个获得了高票的回答是: 全栈工程师是指,一个能处理数据库.服务器.系统工程和客户端的所有工作的工 ...

  4. 阿里巴巴年薪800k大数据全栈工程师成长记

    大数据全栈工程师一词,最早出现于Facebook工程师Calos Bueno的一篇文章 - Full Stack (需fanqiang).他把全栈工程师定义为对性能影响有着深入理解的技术通才.自那以后 ...

  5. Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

  6. EFCodeFirst快速搭建入门

    EFCodeFirst快速搭建入门 1.新建Model类库项目. 添加EntityFramework.dll的引用. 编写实体类Course,Student. namespace EFCodeFirs ...

  7. 测开之Python自动化全栈工程师+性能专项(送思维导图)

    测开之Python自动化全栈工程师+性能专项 功能测试基础 接口测试基础接口的通信原理与本质cookie.session.token详解接口测试的意义与测试方法接口测试用例的设计 app测试 app流 ...

  8. Python全栈工程师(装饰器、模块)

    ParisGabriel                每天坚持手写  一天一篇  决定坚持几年 全栈工程师     Python人工智能从入门到精通 装饰器 decorators(专业提高篇) 装饰 ...

  9. Python全栈工程师(递归函数、闭包)

    ParisGabriel            每天坚持手写  一天一篇  决定坚持几年 全栈工程师     Python人工智能从入门到精通 函数式编程: 是指用一系列函数解决问题 每一个函数完成细 ...

  10. 【目录】python全栈工程师

    第一阶段:Python 语言核心编程1. Python核心   -- 2048 游戏核心算法2. 面向对象   -- 天龙八部游戏技能系统3. Python高级   -- 集成操作框架项目:2048游 ...

随机推荐

  1. SpringBoot课程学习(一)

    @SpringBootTest指定测试的启动类 声明@SpringBootTest @Test注解 @Test 指定测试方法 @Order排序 一:先声明排序模式 @TestMethodOrder(M ...

  2. Codeforces Round #710 (Div. 3)

    emmm,就ac了3题 A题转换推下公式. tB题模拟,在第一个与最后一个变x后,直接i下标+k,判断当前下标前一个befor与最后一个last距离是否>k,是的话在当前下标往前找*字符然后改为 ...

  3. iptables使用详解

    iptables使用详解 @(linux)[iptables] 前言 最近买了一个VPS,并在上面搭了DOCKER,然后再DOCKER中安装Mysql.但只要将网络端口映射到宿主机上,那么外部网络就可 ...

  4. k8s 中的 service 如何找到绑定的 Pod 以及如何实现 Pod 负载均衡

    k8s 中的 service 如何找到绑定的 Pod 以及如何实现 Pod 负载均衡 前言 endpoint kube-proxy userspace 模式 iptables ipvs kernels ...

  5. Python学习笔记----操作字符串

    1.字符串相加.列表相加.列表和字符串不能混着使用 #序列相加 a="hello" b="python" c=a+b print("字符串相加的结果& ...

  6. echarts的使用 超好用的报表制作、数据的图形化展示

    地址链接:https://echarts.apache.org/zh/index.html 1.图形选择 2.对应的js代码

  7. CentOS 7.9 Related Software Directory

    一.CentOS 7.9 Related Software Directory Installing VMware Workstation Pro on Windows Installing Cent ...

  8. git 多个commit 如何合并

    git 多个commit 如何合并 本篇主要介绍一下 git 中多个commit 如何合并, 因为commit 太多 会导致提交记录混乱, 所以有时候会把多个commit 合并成一个 保持提交记录干净 ...

  9. 基于Camera Link和PCIe DMA的多通道视频采集和显示系统

    基于Camera Link和PCIe DMA的多通道视频采集和显示系统 在主机端PCIe驱动的控制和调度下,视频采集与显示系统可以同时完成对多个Camera Link接口视频采集以及Camera Li ...

  10. Mybatis 报错Mapper method 'xxx' has an unsupported return type

    报错原因: 出现这种错误,说明sql语句执行成功,只是返回类型出了问题. 解决方法: insert.delete.update操作默认返回一个int类型的整数,将增删改的接口改成int或者void即可 ...