一.flask实现数据持久化
所谓数据持久化也就是讲数据写入到数据库或者文件中保存。一般我们在代码中操作数据库并不是直接写sql语句,而是使用ORM模型。即以操作类的方式来操作数据库。
1.SQLAlchemy简介
SQLAlchemy是一款ORM模型的数据库框架,可以实现以类的形式来操作数据库。
安装方式:pip install SQLAlchemy
SQLAlchemy操作原生数据库命令
from sqlalchemy import create_engine
# 主机地址
HOSTNAME = 'xxx.xxx.xxx.xxx'
# 数据库
DATABASE = 'test'
# 端口号,一般固定,默认为3306
PORT = 3306
# 用户名和密码
USERNMAE = 'root'
PASSWORD = 'xxx'
# 创建数据库引擎
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNMAE,PASSWORD,HOSTNAME,PORT,DATABASE)
engine = create_engine(DB_URL)
# 使用引擎连接数据库
with engine.connect() as conn:
# 执行sql语句
result = conn.execute("select * from users")
print(result.fetchone())
分析:
- 创建数据库引擎使用sqlalchemy.create_engine(db_url)方法,传入一个数据库url地址作为参数。
- db_url的格式为:
dialect+driver://username:password@host:port/database?charset=utf8
其中dialect表示数据库类型,这里使用的是mysql;driver表示python中连接数据库的驱动,这里使用pymysql;username表示数据库的用户名;password表示连接数据库的密码;host:port表示数据库的地址(ip+端口);database表示数据库名字
2.ORM模型介绍
-
前面我们介绍了使用SQLAlchemy执行原生的sql命令,但实际项目中当我们创建的sql表增多时,使用这种方式将十分不方便且不安全。所以实际项目中我们都是使用ORM模型来操作数据库
-
ORM(Object Relationship Mapping),即对象关系映射,通过ORM模型,我们可以使用类去操作数据库,而不需要写原生的SQL语句。
ORM是通过把数据表映射成代码中的类,把字段作为类的属性,ORM在执行对象操作时最终把对应的操作转换为数据库的原生语句。 -
使用ORM模型,可以减少我们sql语句的使用,且能很好的实现代码复用,对于安全性也能大大增加
3.使用ORM模型创建表
from sqlalchemy import create_engine,Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
# 主机地址
HOSTNAME = 'xxx.xxx.xxx.xxx'
# 数据库
DATABASE = 'test'
# 端口号,一般固定,默认为3306
PORT = 3306
# 用户名和密码
USERNMAE = 'root'
PASSWORD = 'xxx'
# 创建数据库引擎
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNMAE,PASSWORD,HOSTNAME,PORT,DATABASE)
engine = create_engine(DB_URL)
# 生成一个基类,供模型类继承
Base = declarative_base(engine)
# 创建模型类
class Students(Base):
# 指定数据库表名,如果不指定会以类名的小写字母来作为数据库表名
__tablename__ = 'students'
# 给定字段
id = Column(Integer,primary_key=True,autoincrement=True)
name = Column(String(50),nullable=False)
gender = Column(Integer,default=1,comment='1为男,2为女')
# 格式化类的默认输出格式
def __str__(self):
return f"<Student(id={self.id},name={self.name},gender={self.gender})>"
# 将模型映射到数据库中,只有映射后才能在数据库中生效
Base.metadata.create_all()
运行结果如下:
分析:
- 创建模型类时都需要继承declarative_base()创建的基类
__tablename__
:用来指定数据库表名,如果不指定会以类名的小写字母来作为数据库表名- 使用Column()来指定字段的类型,约束属性。第一个参数为数据类型,后面的参数都为字段的约束属性
- 常见的数据类型有:
- Integer:整数类型
- Float:浮点数类型
- Boolean:布尔类型
- DECIMAL:定点类型,可以指定小数的位数和精度
- Enum:枚举类型,指定几个值用于选择
- Date:传递datetime.date()
- Time: 传递datetime.time()
- DateTime: 传递datetime.datetime()
- String: 字符串类型,使用时需要指定长度
- Text:文本类型
- LONGTEXT: 长文本类型
- 常见的约束属性有:
- default
默认值。 - nullable
是否可空。 - primary_key
是否为主键。 - unique
是否唯一。 - autoincrement
是否自动增长。 - onupdate
指定在更新数据的时候执行的函数。 - name
该属性在数据库中的字段映射。
- default
举例:
from datetime import datetime
from sqlalchemy import create_engine,Column, Integer, String,DECIMAL,Boolean,Enum,DateTime
from sqlalchemy.ext.declarative import declarative_base
# 主机地址
HOSTNAME = '192.168.1.102'
# 数据库
DATABASE = 'test'
# 端口号,一般固定,默认为3306
PORT = 3306
# 用户名和密码
USERNMAE = 'root'
PASSWORD = 'xxxx'
# 创建数据库引擎
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNMAE,PASSWORD,HOSTNAME,PORT,DATABASE)
engine = create_engine(DB_URL)
# 生成一个基类,供模型类继承
Base = declarative_base(engine)
# 创建模型类
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
price = Column(DECIMAL(20, 8))
is_delete = Column(Boolean)
btype = Column(Enum('Science', 'Computer'))
release_time = Column(DateTime)
update_time = Column(DateTime, onupdate=datetime.now())
# 将模型映射到数据库中,只有映射后才能在数据库中生效
Base.metadata.create_all()
运行结果如下:
4.使用ORM模型添加数据
from datetime import datetime
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine,Column, Integer, String,DECIMAL,Boolean,Enum,DateTime
from sqlalchemy.ext.declarative import declarative_base
# 主机地址
HOSTNAME = '192.168.1.102'
# 数据库
DATABASE = 'test'
# 端口号,一般固定,默认为3306
PORT = 3306
# 用户名和密码
USERNMAE = 'root'
PASSWORD = 'xxx'
# 创建数据库引擎
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNMAE,PASSWORD,HOSTNAME,PORT,DATABASE)
engine = create_engine(DB_URL)
# 生成一个基类,供模型类继承
Base = declarative_base(engine)
# 创建模型类
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
price = Column(DECIMAL(20, 8))
is_delete = Column(Boolean)
btype = Column(Enum('Science', 'Computer'))
release_time = Column(DateTime)
update_time = Column(DateTime, onupdate=datetime.now())
# 将模型映射到数据库中,只有映射后才能在数据库中生效
# Base.metadata.create_all()
# 使用sessionmaker创建一个session,使用session来完成对数据的增删查改
session = sessionmaker(bind=engine)()
# 添加数据到数据库中
data1 = Book(name='python',price=25.55,is_delete=False,btype='Science',release_time=datetime.now())
data2 = Book(name='java',price=54.23,is_delete=False,btype='Computer',release_time=datetime.now())
data3 = Book(name='c++',price=60.05,is_delete=False,btype='Computer',release_time=datetime.now())
session.add_all([data1, data2, data3])
# 提交数据,必须commit后才能生效
session.commit()
运行后结果如下:
分析:
- 添加数据需要先使用sessionmaker()生成一个关联数据库的session,使用session.add_all()来完成对数据的添加
- 添加完数据后需要使用session.commit()来完成数据的提交
5.使用ORM模型查询数据
5.1 查询所有数据
from datetime import datetime
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine,Column, Integer, String,DECIMAL,Boolean,Enum,DateTime
from sqlalchemy.ext.declarative import declarative_base
# 主机地址
HOSTNAME = '192.168.1.102'
# 数据库
DATABASE = 'test'
# 端口号,一般固定,默认为3306
PORT = 3306
# 用户名和密码
USERNMAE = 'root'
PASSWORD = 'xxx'
# 创建数据库引擎
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNMAE,PASSWORD,HOSTNAME,PORT,DATABASE)
engine = create_engine(DB_URL)
# 生成一个基类,供模型类继承
Base = declarative_base(engine)
# 创建模型类
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
price = Column(DECIMAL(20, 8))
is_delete = Column(Boolean)
btype = Column(Enum('Science', 'Computer'))
release_time = Column(DateTime)
update_time = Column(DateTime, onupdate=datetime.now())
def __str__(self):
return f'<"Book:(id={self.id},name={self.name},price={self.price},btype={self.btype})">'
# 将模型映射到数据库中,只有映射后才能在数据库中生效
# Base.metadata.create_all()
# 使用sessionmaker创建一个session,使用session来完成对数据的增删查改
session = sessionmaker(bind=engine)()
datas = session.query(Book).all()
for data in datas:
print(data)
print(data.name)
print(data.price)
运行结果如下:
分析:
- 使用session.query()来完成对数据的查询
- 返回的对象为包含所有查询数据的可迭代对象
5.2 查询数据的指定字段
from datetime import datetime
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine,Column, Integer, String,DECIMAL,Boolean,Enum,DateTime
from sqlalchemy.ext.declarative import declarative_base
# 主机地址
HOSTNAME = '192.168.1.102'
# 数据库
DATABASE = 'test'
# 端口号,一般固定,默认为3306
PORT = 3306
# 用户名和密码
USERNMAE = 'root'
PASSWORD = 'xxx'
# 创建数据库引擎
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNMAE,PASSWORD,HOSTNAME,PORT,DATABASE)
engine = create_engine(DB_URL)
# 生成一个基类,供模型类继承
Base = declarative_base(engine)
# 创建模型类
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
price = Column(DECIMAL(20, 8))
is_delete = Column(Boolean)
btype = Column(Enum('Science', 'Computer'))
release_time = Column(DateTime)
update_time = Column(DateTime, onupdate=datetime.now())
def __str__(self):
return f'<"Book:(id={self.id},name={self.name},price={self.price},btype={self.btype})">'
# 将模型映射到数据库中,只有映射后才能在数据库中生效
# Base.metadata.create_all()
# 使用sessionmaker创建一个session,使用session来完成对数据的增删查改
session = sessionmaker(bind=engine)()
datas = session.query(Book.id,Book.name).all()
for data in datas:
print(data)
运行结果如下:
分析:
- 在query()中传入指定模型类的属性即可查询指定数据的字段
5.3 对查询的数据进行切片
查询的数据返回的是一个可迭代的对象,所以可以对查询的结果进行切片,也可以进行遍历。
from datetime import datetime
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine,Column, Integer, String,DECIMAL,Boolean,Enum,DateTime
from sqlalchemy.ext.declarative import declarative_base
# 主机地址
HOSTNAME = '192.168.1.102'
# 数据库
DATABASE = 'test'
# 端口号,一般固定,默认为3306
PORT = 3306
# 用户名和密码
USERNMAE = 'root'
PASSWORD = 'xxx'
# 创建数据库引擎
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNMAE,PASSWORD,HOSTNAME,PORT,DATABASE)
engine = create_engine(DB_URL)
# 生成一个基类,供模型类继承
Base = declarative_base(engine)
# 创建模型类
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
price = Column(DECIMAL(20, 8))
is_delete = Column(Boolean)
btype = Column(Enum('Science', 'Computer'))
release_time = Column(DateTime)
update_time = Column(DateTime, onupdate=datetime.now())
def __str__(self):
return f'<"Book:(id={self.id},name={self.name},price={self.price},btype={self.btype})">'
# 将模型映射到数据库中,只有映射后才能在数据库中生效
# Base.metadata.create_all()
# 使用sessionmaker创建一个session,使用session来完成对数据的增删查改
session = sessionmaker(bind=engine)()
datas = session.query(Book.id,Book.name).all()[1:3] # 获取第二三条数据
for data in datas:
print(data)
运行结果如下:
分析:
- 可以使用数组切片的方式对数组进行切片
- 可以使用query(Book.id,Book.name).first()来获取第一条数据
5.4 对查询的数据进行过滤
可以使用filter或者filter_by来对数据进行过滤,获取满足条件的数据。
from datetime import datetime
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine,Column, Integer, String,DECIMAL,Boolean,Enum,DateTime
from sqlalchemy.ext.declarative import declarative_base
# 主机地址
HOSTNAME = '192.168.1.102'
# 数据库
DATABASE = 'test'
# 端口号,一般固定,默认为3306
PORT = 3306
# 用户名和密码
USERNMAE = 'root'
PASSWORD = 'xxx'
# 创建数据库引擎
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNMAE,PASSWORD,HOSTNAME,PORT,DATABASE)
engine = create_engine(DB_URL)
# 生成一个基类,供模型类继承
Base = declarative_base(engine)
# 创建模型类
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
price = Column(DECIMAL(20, 8))
is_delete = Column(Boolean)
btype = Column(Enum('Science', 'Computer'))
release_time = Column(DateTime)
update_time = Column(DateTime, onupdate=datetime.now())
def __str__(self):
return f'<"Book:(id={self.id},name={self.name},price={self.price},btype={self.btype})">'
# 将模型映射到数据库中,只有映射后才能在数据库中生效
# Base.metadata.create_all()
# 使用sessionmaker创建一个session,使用session来完成对数据的增删查改
session = sessionmaker(bind=engine)()
datas = session.query(Book).filter(Book.name=='python').all()
for data in datas:
print(data)
print('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
datas = session.query(Book).filter_by(name='python').all()
for data in datas:
print(data)
运行结果如下:
分析:
-
filter和filter_by都可以对数据进行过滤,不同之处在于filter()传入判断条件作为参数。filter_by()传入关键字作为参数
-
filter常用的过滤条件有:
-
equals
filter(Book.name == 'Name 3')
-
not equals
filter(Book.name != 'Name 3')
-
like
filter(Book.name.like("%Name%")) # %用来表示任意字符
-
in
filter(Book.name.in_(['Name 1', 'Name 2'])) # in_的参数也可以是query的查询结果 filter(Book.name.in_(session.query(Book.name).filter(Book.name.like('%Name%'))))
-
not in
filter(~Book.name.in_(['Name 1', 'Name 2']))
-
is null
filter(Book.name == None) # 或者是 filter(Book.name.is_(None))
-
is not null
filter(User.name != None) # 或者是 filter(User.name.isnot(None))
-
and
filter(Book.name == 'Name 1', Book.price <= 50).all() filter(and_(Book.name == 'Name 1', Book.price <= 50)).all() filter(Book.name == 'Name 1').filter(Book.price <= 50).all()
-
or
filter(or_(Book.name == 'Name 1', Book.price >= 50)).all()
5.5 对查询的结果使用聚合函数
from datetime import datetime from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine, Column, Integer, String, DECIMAL, Boolean, Enum, DateTime, func from sqlalchemy.ext.declarative import declarative_base # 主机地址 HOSTNAME = '192.168.1.102' # 数据库 DATABASE = 'test' # 端口号,一般固定,默认为3306 PORT = 3306 # 用户名和密码 USERNMAE = 'root' PASSWORD = 'xxx' # 创建数据库引擎 DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNMAE,PASSWORD,HOSTNAME,PORT,DATABASE) engine = create_engine(DB_URL) # 生成一个基类,供模型类继承 Base = declarative_base(engine) # 创建模型类 class Book(Base): __tablename__ = 'book' id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(50), nullable=False) price = Column(DECIMAL(20, 8)) is_delete = Column(Boolean) btype = Column(Enum('Science', 'Computer')) release_time = Column(DateTime) update_time = Column(DateTime, onupdate=datetime.now()) def __str__(self): return f'<"Book:(id={self.id},name={self.name},price={self.price},btype={self.btype})">' # 将模型映射到数据库中,只有映射后才能在数据库中生效 # Base.metadata.create_all() # 使用sessionmaker创建一个session,使用session来完成对数据的增删查改 session = sessionmaker(bind=engine)() datas = session.query(func.sum(Book.price)).all() for data in datas: print(data)
运行结果如下:
-
分析:
- 可以在query中使用聚合函数,对数据进行操作
- 常见的聚合函数有:
- func.count()
统计记录的数量。 - func.avg()
求平均值。 - func.max()
求最大值。 - func.min()
求最小值。 - func.sum()
求和。
- func.count()
6. ORM模型之删除数据
from datetime import datetime
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine, Column, Integer, String, DECIMAL, Boolean, Enum, DateTime, func
from sqlalchemy.ext.declarative import declarative_base
# 主机地址
HOSTNAME = '192.168.1.102'
# 数据库
DATABASE = 'test'
# 端口号,一般固定,默认为3306
PORT = 3306
# 用户名和密码
USERNMAE = 'root'
PASSWORD = 'xxx'
# 创建数据库引擎
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNMAE,PASSWORD,HOSTNAME,PORT,DATABASE)
engine = create_engine(DB_URL)
# 生成一个基类,供模型类继承
Base = declarative_base(engine)
# 创建模型类
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
price = Column(DECIMAL(20, 8))
is_delete = Column(Boolean)
btype = Column(Enum('Science', 'Computer'))
release_time = Column(DateTime)
update_time = Column(DateTime, onupdate=datetime.now())
def __str__(self):
return f'<"Book:(id={self.id},name={self.name},price={self.price},btype={self.btype})">'
# 将模型映射到数据库中,只有映射后才能在数据库中生效
# Base.metadata.create_all()
# 使用sessionmaker创建一个session,使用session来完成对数据的增删查改
session = sessionmaker(bind=engine)()
data = session.query(Book).first()
session.delete(data)
session.commit()
运行结果如下:
分析:删除数据需要先查询到数据,然后使用session.delete()删除数据,最后使用commit()提交
7.ORM模型之修改数据
from datetime import datetime
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine, Column, Integer, String, DECIMAL, Boolean, Enum, DateTime, func
from sqlalchemy.ext.declarative import declarative_base
# 主机地址
HOSTNAME = '192.168.1.102'
# 数据库
DATABASE = 'test'
# 端口号,一般固定,默认为3306
PORT = 3306
# 用户名和密码
USERNMAE = 'root'
PASSWORD = 'ouyi1994'
# 创建数据库引擎
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNMAE,PASSWORD,HOSTNAME,PORT,DATABASE)
engine = create_engine(DB_URL)
# 生成一个基类,供模型类继承
Base = declarative_base(engine)
# 创建模型类
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
price = Column(DECIMAL(20, 8))
is_delete = Column(Boolean)
btype = Column(Enum('Science', 'Computer'))
release_time = Column(DateTime)
update_time = Column(DateTime, onupdate=datetime.now())
def __str__(self):
return f'<"Book:(id={self.id},name={self.name},price={self.price},btype={self.btype})">'
# 将模型映射到数据库中,只有映射后才能在数据库中生效
# Base.metadata.create_all()
# 使用sessionmaker创建一个session,使用session来完成对数据的增删查改
session = sessionmaker(bind=engine)()
data = session.query(Book).first()
data.name = 'linux'
session.commit()
运行结果如下:
分析:先查询数据,然后修改数据,最后使用commit()提交
8.ORM模型之外键约束
8.1 创建外键约束
from datetime import datetime
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine, Column, Integer, String, DECIMAL, Boolean, Enum, DateTime, func, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
# 主机地址
HOSTNAME = '192.168.1.102'
# 数据库
DATABASE = 'test'
# 端口号,一般固定,默认为3306
PORT = 3306
# 用户名和密码
USERNMAE = 'root'
PASSWORD = 'xxx'
# 创建数据库引擎
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNMAE,PASSWORD,HOSTNAME,PORT,DATABASE)
engine = create_engine(DB_URL)
# 生成一个基类,供模型类继承
Base = declarative_base(engine)
class Class(Base):
__tablename__ = 'class'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(10),nullable=False)
def __str__(self):
return f'<"Class:(id={self.id},name={self.name})">'
class Student(Base):
__tablename__ = 'student'
id = Column(Integer,primary_key=True,autoincrement=True)
name = Column(String(10),nullable=False)
c_id = Column(Integer,ForeignKey("class.id",ondelete='RESTRICT')) # 将class表中的id作为外键
Base.metadata.create_all()
# 使用sessionmaker创建一个session,使用session来完成对数据的增删查改
session = sessionmaker(bind=engine)()
class1 = Class(name='1班')
class2 = Class(name='1班')
student1 = Student(name='zhangsan',c_id='1')
student2 = Student(name='lisi',c_id='2')
session.add_all([class1,class2,student1,student2])
session.commit()
运行结果如下:
分析:
- 使用ForeignKey()用来创建外键,传入
表名.字段
作为第一个参数,第二个参数传入ondelete='RESTRICT’用来设置外键的约束级别 - MySQL中的外键约束有以下几个级别:
- RESTRICT
严格模式,若子表中有父表对应的关联数据,删除父表对应数据,会阻止删除,也是默认项。 - NO ACTION
在MySQL中,同RESTRICT。 - CASCADE
级联模式,父表操作后,对应子表关联的数据也进行操作。 - SET NULL
置空模式,父表被操作之后,子表对应的外键字段被置空。
- RESTRICT
8.2 设置表关系
两个表之间存在外键关联后,可以设置两个表的表关系。
常见的表关系有以下几种:一对多关系,一对一关系,多对多关系
一对一关系
from datetime import datetime
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy import create_engine, Column, Integer, String, DECIMAL, Boolean, Enum, DateTime, func, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
# 主机地址
HOSTNAME = '192.168.1.102'
# 数据库
DATABASE = 'test'
# 端口号,一般固定,默认为3306
PORT = 3306
# 用户名和密码
USERNMAE = 'root'
PASSWORD = 'xxx'
# 创建数据库引擎
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNMAE,PASSWORD,HOSTNAME,PORT,DATABASE)
engine = create_engine(DB_URL)
# 生成一个基类,供模型类继承
Base = declarative_base(engine)
class Banji(Base):
__tablename__ = 'class'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(10),nullable=False)
student = relationship('Student')
def __str__(self):
return f'<"Class:(id={self.id},name={self.name})">'
class Student(Base):
__tablename__ = 'student'
id = Column(Integer,primary_key=True,autoincrement=True)
name = Column(String(10),nullable=False)
c_id = Column(Integer,ForeignKey("class.id",ondelete='RESTRICT')) # 将class表中的id作为外键
class0 = relationship('Banji')
Base.metadata.create_all()
# 使用sessionmaker创建一个session,使用session来完成对数据的增删查改
session = sessionmaker(bind=engine)()
banji1 = Banji(name='1班')
student1 = Student(name='zhanshan',class0=banji1)
session.add_all([student1]) # 添加一个表的数据时,会自动添加另一个表关联的数据
session.commit()
student2 = Student(name="lisi")
student3 = Student(name='wangwu')
banji2 = Banji(name='2班',student=[student2,student3]) # 主表关联的子表字段为列表
session.add_all([banji2]) # # 添加一个表的数据时,会自动添加另一个表关联的数据
session.commit()
运行结果如下:
分析:
- 两个存在外键约束的表可以使用relationship来创建表关系,参数为
关联表模型类名字
- 对于存在表关系的数据,提交一个表数据时,另一个表的数据也会自动提交
- 存在外键的子表对应多,所以使用主表的关联字段查询的内容为列表
一对一关系
student = relationship('Student',uselist=False) #将uselist设置为False,取消列表属性,从而实现一对一关系
分析:
要实现两个存在外键约束的表,实现一对一关系。只需要在主表的relationship中传入uselist=False即可
多对多关系
要实现两个表的多对多关系,需要借助第三个表来实现
举例:实现teacher和banji表的多对多关系
teacher_classes = Table(
'table_classes',
Base.metadata,
Column('teacher_id', Integer, ForeignKey('teacher.id')),
Column('classes_id', Integer, ForeignKey('classes.id')),
)
class Teacher(Base):
__tablename__ = 'teacher'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
classes = relationship('Classes', backref='teachers', secondary=teacher_classes)
class Classes(Base):
__tablename__ = 'classes'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
通过Table类来创建中间表,可以看到,初始化时的第1个参数teacher_classes代表的是中间表的表名,第2个参数是Base的元数据,第3个和第4个参数就是要连接的两个表,其中Column第1个参数是连接表的外键名,第2个参数是这个外键的类型,第3个参数是要连接的两个表的表名和字段。
9.ORM模型之limit,offset
- limit:用来限制输出几条记录
- offset:用来设置输出的记录的偏移量
session.query(Article).offset(3).limit(3).all() # 输出第4,5,6条记录
10.ORM模型之排序
方式一:order_by
session.query(Article).order_by(Article.length).all() # 正序
session.query(Article).order_by(Article.length.desc()).all() # 倒序
方式二:在模型定义时声明
class Article(Base):
__tablename__ = 'article'
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(50), nullable=False)
length = Column(Integer)
def __str__(self):
return 'User(id: {}, name: {}, length: {})'.format(self.id, self.title, self.length)
# 使用`__mapper_args__`指定默认排序方式,如果要倒序,在字段后面加上desc().
__mapper_args__ = {
'order_by':length
}
11.ORM模型之group_by和having
我们可以使用group_by来进行分组,使用having来实现对分组后的数据进行过滤
session.query(User.age, func.count(User.id)).group_by(User.age).having(User.age > 18).all()
# 获取年龄大于18的各个年龄段的人数
12.falsk中操作flask-sqlalchemy
SQLAlchemy是独立于flask的,但是有一个flask-sqlalchemy插件对sqlalchemy进行了封装,使得我们在flask中操作sqlalchemy更加方便
安装flask-sqlalchemy
pip install flask-sqlalchemy
使用
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_sqlalchemy'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URL
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(30))
def __repr__(self):
return 'User(id: {}, name: {})'.format(self.id, self.name)
class Article(db.Model):
__tablename__ = 'article'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(50))
uid = db.Column(db.Integer, db.ForeignKey('users.id'))
author = db.relationship('User', backref='articles')
def __repr__(self):
return 'User(id: {}, title: {})'.format(self.id, self.title)
db.drop_all()
db.create_all()
# 添加数据
user = User(name='Corley')
article = Article(title='Python')
article.author = user
db.session.add(article)
db.session.commit()
# 查询数据
user = User.query.all()
print(user)
@app.route('/')
def index():
return '首页'
if __name__ == '__main__':
app.run(debug=True)
flask-sqlalchemy中查询添加数据等操作与sqlalchemy都差不多。这里不做详细讲解,需要的时候可以百度或者参考官方文档。