目录
一.SQLALchemy
SQLAlchemy对象关系映射器提供了一种方法,用于将用户定义的Python类与数据库表相关联,并将这些类(对 象)的实例与其对应表中的行相关联。它包括一个透明地同步对象及其相关行之间状态的所有变化的系统,称为工 作单元,以及根据用户定义的类及其定义的彼此之间的关系表达数据库查询的系统。
1.安装:
flask要操作数据库,必须要安装pymysql,SQLALchemy,着两个都可以pip install 安装
pip install pymysql
pip install SQLALchemy
2.连接
from sqlalchemy import create_engine
# 数据库的配置信息
HOSTNAME = '127.0.0.1' # 数据库所在的主机地址
PORT = '3306' # 端口号
DATABASE = 'test' # 数据库名字
USERNAME = 'root' # 数据库用户名
PASSWORD = 'root' # 数据库密码
DB_URI = 'mysql+pymysql://{}:{}@{}?charset=utf8mb4:{}/{}'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)
# 创建数据库引擎
engine=create_engine(DB_URI)
# 创建连接
conn=engine.connect()
# 关闭连接
conn.close()
二:创建OBM映射
创建一个类,一个类对应了一个数据库中的一张表,类的数据属性对应了表中的字段名,这个类称为映射类。 根据映射类创建出一个一个的对象,每个对象对应了表中的一条实际的数据。
flask中给我们提供了一个declarative_base()函数来基类,也就是我们创建的映射类都要继承这个基类。
from sqlalchemy.ext.declarative import declarative_base
engine=create_engine(DB_URI)
# 创建基类
Base=declarative_base(engine)
class Student(Base):
# 用Base类作为基类来写之间的ORB类,要使用__tablename__来定义一个表名
__tablename__='student'
class Student2(Base):
__tablename__='student2'
# 这里的操作和数据库差不多,之所以叫做映射,是因为将python中的数据映射为数据库中的字段了
# 在python中的Integer映射到数据库中叫作整形,也就是int类型
# Column翻译过来叫做栏目,也就是数据库中字段名的哪一行,也就是将id,name,age映射到数据库中成字段名
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50))
age = Column(Integer)
weight= Column(Float(50))
SQLALchemy常用数据类型
1. Integer:整形,映射到数据库中是int类型。
2. Float:浮点类型,映射到数据库中是float类型。他占据的32位。
3. Double:双精度浮点类型,映射到数据库中是double类型,占据64位 (SQLALCHEMY中没有)。
4. String:可变字符类型,映射到数据库中是varchar类型.
5. Boolean:布尔类型,映射到数据库中的是tinyint类型。
6. DECIMAL:定点类型。是专门为了解决浮点类型精度丢失的问题的。在存储钱相关的字段的时候建议大家都 使用这个数据类型。并且这个类型使用的时候需要传递两个参数,第一个参数是用来标记这个字段总能能存 储多少个数字,第二个参数表示小数点后有多少位。
7. Enum:枚举类型。指定某个字段只能是枚举中指定的几个值,不能为其他值。在ORM模型中,使用Enum来 作为枚举。
8. Date:存储时间,只能存储年月日。映射到数据库中是date类型。在Python代码中,可以使用 datetime.date 来指定。
9. DateTime:存储时间,可以存储年月日时分秒毫秒等。映射到数据库中也是datetime类型。在Python代码 中,可以使用 datetime.datetime 来指定。
10. Time:存储时间,可以存储时分秒。映射到数据库中也是time类型。在Python代码中,可以使用 datetime.time 来创建值。
11. Text:存储长字符串。一般可以存储6W多个字符。如果超出了这个范围,可以使用LONGTEXT类型。映射到 数据库中就是text类型。
12. LONGTEXT:长文本类型,映射到数据库中是longtext类型。
column常用参数
1. primary_key:True设置某个字段为主键。
2. autoincrement:True设置这个字段为自动增长的。
3. default:设置某个字段的默认值。在发表时间这些字段上面经常用。
4. nullable:指定某个字段是否为空。默认值是True,就是可以为空。
5. unique:指定某个字段的值是否唯一。默认是False。
6. onupdate:在数据更新的时候会调用这个参数指定的值或者函数。在第一次插入这条数据的时候,不会用 onupdate的值,只会使用default的值。常用于是 update_time 字段(每次更新数据的时候都要更新该字段 值)。
7. name:指定ORM模型中某个属性映射到表中的字段名。如果不指定,那么会使用这个属性的名字来作为字 段名。如果指定了,就会使用指定的这个值作为表字段名。这个参数也可以当作位置参数,在第1个参数来指 定。
三:数据的CRUD操作
用session做数据的增删改查
1.构建session对象
所有和数据库ORM操作都必须通过一个叫做session的会话对象来实现,通过一下代码来湖区会话对象
from sqlalchemy.orm import sessionmaker
engine=create_engine(DB_URL)
Base=declarative_base(engine)
session=sessionmaker(engine)() # 返回的是一个session对象
2.添加对象
# 创建对象,也就是创建一条数据
p1=Student2(name='zhangsan',age=19,weight=100)
# 将这个对象添加到session会话对象中
session.add(p1)
# 将session中的对象提交
session.commit()
# 一次性添加多个数据
p1=Student2(name='zhangsan',age=19,weight=100)
p2=Student2(name='lisi',age=20,weight=200)
session.add_all([p1,p2])
session.commit()
3.查找对象
# 查找某个模型对应的表中的所有数据
all_student=session.query(Student2).all()
# 使用filter_by来做条件查询
all_student=session.query(Student2).filter_by(name=='zhangsan').all()
# 使用filter来做条件查询
all_student=session.query(Student2).fiter(Student2.name=='zhangsan').all()
# 使用get方法查找数据,get方法是根据id来查找的,只会返回一条数据或者None
student=session.query(Student2).get(1)
# 使用first方法来获取价格集中的一条数据
student=session.query(Student2).first()
4.修改对象
先使用session查找到数据库中的数据,然后就可以对着条数据修改,修改好后使用commit提交
student=session.query(Student).first()
session.delete(student)
session.commit()
5.删除对象
先使用session找到数据库中的数据,然后使用session.delete方法将着条数据删除,最后使用commit提交
student= session.query(Student2).first()
session.delete(student)
session.commit()
四:ORM的关联关系
1.表的外键关联一对多
使用SQLAlchemy创建外键非常简单。在从表中增加一个字段,指定这个字段外键的是哪个表的哪个字段就可以 了。从表中外键的字段,必须和主表的主键字段类型保持一致。
class Student3(Base):
__tablename__='user'
id = Column(Integer,primary_key=True,autoincrement=True)
uname = Column(String(50),nullable=False)
def __repr__(self):
return "<User(uname:%s)>" % self.uname
class Student4(Base):
__tablename__ = 'news'
id = Column(Integer,primary_key=True,autoincrement=True)
title = Column(String(50),nullable=False)
content = Column(Text,nullable=False)
# ForeignKey关键字指定关联另外一个表的字段
uid = Column(Integer,ForeignKey("user.id"))
连接的两个表的删除选项
1. RESTRICT:若子表中有父表对应的关联数据,删除父表对应数据,会阻止删除。默认项
2. NO ACTION:在MySQL中,同RESTRICT。
3. CASCADE:级联删除。
4. SET NULL:父表对应数据被删除,子表对应数据项会设置为NULL。
2.ORM中的一对多和多对一
在mysql中表级别的外键,必须要拿到一个表的外键,才能通过这个外键在去另外一张表中查找
而SQLALchemy提供了一个relationship类,这个类可以定义属性,以后再访问这个类相关联的表的时候就可以直接通过这个属性访问的。另外,可以通过backref来指定反向访问的属性名称,比如relationship是A,A指定了B,那么backref就可以指定一个属性来使B反向访问A
class User(Base):
__tablename__='user'
id = Column(Integer,primary_key=True,autoincrement=True)
uname = Column(String(50),nullable=False)
def __repr__(self):
return "<User(uname:%s)>" % self.uname
class News(Base):
__tablename__ = 'news'
id = Column(Integer,primary_key=True,autoincrement=True)
title = Column(String(50),nullable=False)
content = Column(Text,nullable=False)
# ForeignKey关键字指定关联另外一个表的字段
uid = Column(Integer,ForeignKey("user.id"))
# 正向author=relationship('User'),表示author这个键连接User这个表而一个这个键可以查询User表多个值,所以叫一对多
# 正向和反向再一起,对于User表也可以通过newss这个名字来反向查询news着张表了
author=relationship('User',backref='newss')
3.ORM中的一对一
在sqlalchemy中,如果想要将两个模型映射成一对一的关系,那么应该在父模型中,指定引用的时候,要传递一 个 uselist=False 这个参数进去。就是告诉父模型,以后引用这个从模型的时候,不再是一个列表了,而是一个 对象了。
方法一:参照一对多关联,加上uselist
class User(Base):
__tablename__ = 'user'
id = Column(Integer,primary_key=True,autoincrement=True)
uname = Column(String(50),nullable=False)
extend = relationship("UserExtend",uselist=False)
class UserExtend(Base):
__tablename__ = 'user_extend'
id = Column(Integer, primary_key=True, autoincrement=True)
school = Column(String(50))
uid = Column(Integer,ForeignKey("user.id"))
user = relationship("User")
方法二:
class User(Base):
__tablename__ = 'user'
id = Column(Integer,primary_key=True,autoincrement=True)
uname = Column(String(50),nullable=False)
class UserExtend(Base):
__tablename__ = 'user_extend'
id = Column(Integer, primary_key=True, autoincrement=True)
school = Column(String(50))
uid = Column(Integer,ForeignKey("user.id"))
user = relationship("User",backref=backref("extend",uselist=False))
4.ORM中的多对多
1. 多对多的关系需要通过一张中间表来绑定他们之间的关系。
2. 先把两个需要做多对多的模型定义出来
3. 使用Table定义一个中间表,中间表一般就是包含两个模型的外键字段就可以了,并且让他们两个来作为一 个“复合主键”。
4. 在两个需要做多对多的模型中随便选择一个模型,定义一个relationship属性,来绑定三者之间的关系,在使 用relationship的时候,需要传入一个secondary=中间表对象名
#表3 中间表
news_tag = Table(
"news_tag",
Base.metadata,
Column("news_id",Integer,ForeignKey("news.id"),primary_key=True),
Column("tag_id",Integer,ForeignKey("tag.id"),primary_key=True)
)
#表1
class News(Base):
__tablename__ = 'news'
id = Column(Integer,primary_key=True,autoincrement=True)
title = Column(String(50),nullable=False)
#产生关系 写法1
# tags = relationship("Tag",backref="newss",secondary=news_tag)
def __repr__(self):
return "<News(title:%s)>" % self.title
#表2
class Tag(Base):
__tablename__ = 'tag'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
# 产生关系 写法2
newss = relationship("News",backref="tags",secondary=news_tag)
def __repr__(self):
return "<Tag(name:%s)>" % self.name
五:SQLALchemy的高级
1.排序
order_by方法排序:可以指定根据模型中某个属性进行排序,"模型名.属性名.desc()"代表的是降序排序。
# 倒序排序
articles2 = session.query(Article).order_by(Article.create_time.desc()).all()
print(articles2)
在定义模型的时候指定排序:有些时候,不想每次在查询的时候都用order_by方法,可以在定义模型的时候 就指定排序的方式。
#排序方式2:定义模型时,指定排序方式
class Article(Base):
__tablename__ = 'article'
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(50), nullable=False)
create_time = Column(DateTime, nullable=False, default=datetime.now)
__mapper_args__ = {
# "order_by": create_time #正序
"order_by": create_time.desc() #倒序
}
def __repr__(self):
return "<Article(title:%s,create_time:%s)>" % (self.title,self.create_time)
2.在relationship的方法中order_by属性
#排序方式3:涉及两表时,定义模型时,用relationship方法中的order_by属性指定排序方式
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True, autoincrement=True)
uname = Column(String(50),nullable=False)
class Article(Base):
__tablename__ = 'article'
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(50), nullable=False)
create_time = Column(DateTime, nullable=False, default=datetime.now)
uid = Column(Integer,ForeignKey("user.id"))
# author = relationship("User",
backref=backref("articles",order_by=create_time)) #正序
author = relationship("User",
backref=backref("articles",order_by=create_time.desc())) #倒序
def __repr__(self):
return "<Article(title:%s,create_time:%s)>" % (self.title,self.create_time)
2.分页查询
(1). limit:可以限制查询的时候只查询前几条数据。 属top-N查询
articles = session.query(Article).limit(10).all()
print(articles)
(2). offset:可以限制查找数据的时候过滤掉前面多少条。可指定开始查询时的偏移量
#offset:可以限制查找数据的时候过滤掉前面多少条。可指定开始查询时的偏移量。
articles = session.query(Article).offset(10).limit(10).all()
3. 切片:可以对Query对象使用切片操作,来获取想要的数据。 可以使用 slice(start,stop) 方法来做切片操作。 也可以使用 [start:stop] 的方式来进行切片操作。 一般在实际开发中,中括号的形式是用得比较多的。
#实现分页
from sqlalchemy.orm.query import Query
def oper3():
articles = session.query(Article).order_by(Article.id.desc()).slice(0,10).all()
print(articles)
def oper4():
articles = session.query(Article).order_by(Article.id.desc())[0:10]
print(articles)