ORM的全称是:Object Relational Mapping (对象 关系 映射)
简单的说,orm是通过使用描述对象和数据之间映射的元数据,将程序中的对象自动持久化到关系数据库中。
ORM需要解决的问题是,能否把对象的数据直接保存到数据库中,又能否直接从数据库中拿到一个对象?要想做到上面两点,则必须要有映射关系。
ORM的优缺点
优点:
- 提高开发效率
- 在一个地方编写数据模型,就可以更轻松地更新,维护和重用代码。
- 它迫使您编写MVC代码,最终使您的代码更简洁。
- 不必编写格式不好的SQL(大多数Web程序员确实很讨厌它,因为SQL被视为一种“子”语言,而实际上却是一种非常强大和复杂的语言)。
- 使用准备好的语句或事务就像调用方法一样简单。
缺点:
- orm会牺牲程序的执行效率和会固定思维模式,在从系统结构上来看,采用orm的系统多是多层系统的,系统的层次太多,效率就会降低。
- orm是一种完全面向对象的做法,所以面向对象的做法也会对性能产生一定的影响。
- orm不是轻量级的工具;它不是功能强大的工具。 您必须进行设置。
- 对于常规查询而言,性能还可以,但是对于大型项目,SQL管理员始终可以使用自己的SQL来做得更好。
常用的ORM
- Java:Hibernate。
- PHP:Propel或Doctrine
- Python:Django ORM或SQLAlchemy(推荐)
- C#:NHibernate或实体框架
如果要在Web编程中尝试ORM库,最好使用完整的框架堆栈,例如:
- Symfony(PHP,使用Propel或Doctrine)
- Django(Python,使用内部ORM)
SQLAlchemy:
sqlalchemy中文文档:
https://www.osgeo.cn/sqlalchemy/orm/tutorial.html
sqlalchemy官方文档:
https://docs.sqlalchemy.org/en/14/
在Python中,最有名的ORM框架是SQLAlchemy,比Django自带的ORM要好那么一点点。
常用的SQLAlchemy字段类型
模型字段类型名 | python中数据类型 | 说明 |
---|---|---|
Integer | int | 普通整数,一般是32位 |
SmallInteger | int | 取值范围小的整数,一般是16位 |
BigInteger | int或long | 不限制精度的整数 |
Float | float | 浮点数 |
Numeric | decimal.Decimal | 普通数值,一般是32位 |
String | str | 变长字符串 |
Text | str | 变长字符串,对较长或不限长度的字符串做了优化 |
LongText | str | 长文本类型 |
Unicode | unicode | 变长Unicode字符串 |
UnicodeText | unicode | 变长Unicode字符串,对较长或不限长度的字符串做了优化 |
Boolean | bool | 布尔值 |
Date | datetime.date | 日期 |
Time | datetime.time | 时间 |
DateTime | datetime.datetime | 日期和时间 |
DECIMAL | decimal.Decimal | 定点类型 |
Enum | str | 枚举类型 |
常用的SQLAlchemy列约束选项
选项名 | 说明 |
---|---|
primary_key | 如果为True,代表表的主键 |
unique | 如果为True,代表这列不允许出现重复的值 |
index | 如果为True,为这列创建索引,提高查询效率 |
nullable | 如果为True,允许有空值,如果为False,不允许有空值 |
default | 为这列定义默认值 |
autoincrement | 是否自动增长 |
onupdate | 更新的时候执行的函数 |
name | 该属性在数据库中的字段映射 |
query可用参数:
- 模型对象。指定查找这个模型中所有的对象。
- 模型中的属性。可以指定只查找某个模型的其中几个属性。
- 聚合函数:
选项名 | 说明 |
---|---|
func.count | 统计行的数量 |
func.avg | 求平均值 |
func.max | 求最大值 |
func.min | 求最小值 |
func.sum | 求和 |
过滤方法:
过滤是数据 提取的一个很重要的功能,以下对一些常用的过滤条件进行详解,并且这些过滤条件都是只能通过filter方法实现的:
- equals 等于:
query.filter(User.name == 'ed')
- not equals 不等于:
query.filter(User.name != 'ed')
- like 模糊查询:
query.filter(User.name.like('%ed%'))
- in …在…里:
query.filter(User.name.in_(['ed','wendy','jack']))
#同时
query.filter(User.name.in_(session.query(User.name).filter(User.name.like('%ed%'))))
- not in …不在…里:
query.filter(~User.name.in_('ed','wendy','jack'))
- is null 为空:
query.filter(User.name==None)
query.filter(User.name.is_(None))
- is not null 不为空:
query.filter(User.name != None)
query.filter(User.name.isnot(None)
- and 与:
from sqlalchemy import and_
query.filter(and_(User.name=='ed', User.fullname=='Ed Jones'))
# 或者
query.filter(User.name=='ed', User.fullname=='Ed Jones')
# 或者
query.filter(User.name=='ed',).filter(User.fullname=='Ed Jones')
- or 或:
from sqlalchemy import or_
query.filter(or_(User.name='ed', User.name='wendy'))
数据库基本操作
- 在Flask-SQLAlchemy中,添加、修改、删除操作,均由数据库会话管理。
- 会话用 db.session 表示。在准备把数据写入数据库前,要先将数据添加到会话中然后调用 db.commit() 方法提交会话。
- 在 Flask-SQLAlchemy 中,查询操作是通过 query 对象操作数据。
- 最基本的查询是返回表中所有数据,可以通过过滤器进行更精确的数据库查询。
问题简述:
1.要爬一个小说网站将文本存在数据库里
代码模块:
通过pip安装SQLAlchemy:
pip install sqlalchemy
导入模块 创建表对象模块代码:
from sqlalchemy import Column, String, create_engine, Integer, Text, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship
# relationship两个表之间的外键关系
from sqlalchemy.ext.declarative import declarative_base
# 创建对象的基类:
Base = declarative_base()
# 定义Book对象
class Book(Base):
# 定义数据库表名
__tablename__ = 'b_data'
# 表的结构 参数参照上面表单
id = Column(Integer, primary_key=True, comment='主键ID')
img_name = Column(String(50), comment="书封面")
book_name = Column(String(50), comment='书名')
author = Column(String(50), comment='作者名')
book_type = Column(String(50), comment='小说类型')
book_byte = Column(String(255), comment='小说字数')
brief_introduction = Column(String(255), comment='小说简介')
books_text = relationship('Book_text', backref='b_data') # relationship两个表之间的外键关系
def __repr__(self):
return self.book_name
# __repr__() 是一个非常特殊的方法,它是一个“自我描述”的方法,该方法通常用于实现这样一个功能:当程序员直接打印该对象时,系统将会输出该对象的“自我描述”信息,用来告诉外界该对象具有的状态信息。
# 定义Book_text对象
class Book_text(Base):
__tablename__ = 'b_text'
id = Column(Integer(), primary_key=True, comment='主键ID')
book_chapter = Column(String(50), comment='章节名')
chapter_text = Column(Text(), comment='章节内容')
book_data_id = Column(Integer,ForeignKey('b_data.id'))
# 初始化数据库连接:
engine = create_engine('mysql+pymysql://root:123456@127.0.0.1:3306/books', echo=True)
# 创建一个会话
Session = sessionmaker(bind=engine)
# 创建session对象:
session = Session()
aaa = '白帝,武帝'
# 添加一条数据到数据库
new_page = Book_text(book_chapter='境界划分', chapter_text=aaa,book_data_id=1)
# 添加到session:
session.add(new_page)
# 提交即保存到数据库:
session.commit()
# 关闭session:
session.close()
# 查询一条数据:
a = session.query(Book_text).get(1)
print(a)
# 查询 a 的chapter_text 里的数据
print(a.chapter_text)