python自动化(七)自动化测试平台开发:2.flask技术讲解下

一.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())

分析:

  1. 创建数据库引擎使用sqlalchemy.create_engine(db_url)方法,传入一个数据库url地址作为参数。
  2. db_url的格式为:dialect+driver://username:password@host:port/database?charset=utf8其中dialect表示数据库类型,这里使用的是mysql;driver表示python中连接数据库的驱动,这里使用pymysql;username表示数据库的用户名;password表示连接数据库的密码;host:port表示数据库的地址(ip+端口);database表示数据库名字

2.ORM模型介绍

  1. 前面我们介绍了使用SQLAlchemy执行原生的sql命令,但实际项目中当我们创建的sql表增多时,使用这种方式将十分不方便且不安全。所以实际项目中我们都是使用ORM模型来操作数据库

  2. ORM(Object Relationship Mapping),即对象关系映射,通过ORM模型,我们可以使用类去操作数据库,而不需要写原生的SQL语句。
    ORM是通过把数据表映射成代码中的类,把字段作为类的属性,ORM在执行对象操作时最终把对应的操作转换为数据库的原生语句。

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

运行结果如下:

在这里插入图片描述

分析:

  1. 创建模型类时都需要继承declarative_base()创建的基类
  2. __tablename__:用来指定数据库表名,如果不指定会以类名的小写字母来作为数据库表名
  3. 使用Column()来指定字段的类型,约束属性。第一个参数为数据类型,后面的参数都为字段的约束属性
  4. 常见的数据类型有:
    1. Integer:整数类型
    2. Float:浮点数类型
    3. Boolean:布尔类型
    4. DECIMAL:定点类型,可以指定小数的位数和精度
    5. Enum:枚举类型,指定几个值用于选择
    6. Date:传递datetime.date()
    7. Time: 传递datetime.time()
    8. DateTime: 传递datetime.datetime()
    9. String: 字符串类型,使用时需要指定长度
    10. Text:文本类型
    11. LONGTEXT: 长文本类型
  5. 常见的约束属性有:
    1. default
      默认值。
    2. nullable
      是否可空。
    3. primary_key
      是否为主键。
    4. unique
      是否唯一。
    5. autoincrement
      是否自动增长。
    6. onupdate
      指定在更新数据的时候执行的函数。
    7. name
      该属性在数据库中的字段映射。

举例:

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()

运行后结果如下:

在这里插入图片描述

分析:

  1. 添加数据需要先使用sessionmaker()生成一个关联数据库的session,使用session.add_all()来完成对数据的添加
  2. 添加完数据后需要使用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)

运行结果如下:
在这里插入图片描述

分析:

  1. filter和filter_by都可以对数据进行过滤,不同之处在于filter()传入判断条件作为参数。filter_by()传入关键字作为参数

  2. filter常用的过滤条件有:

    1. equals

      filter(Book.name == 'Name 3')
      
    2. not equals

      filter(Book.name != 'Name 3')
      
    3. like

      filter(Book.name.like("%Name%")) # %用来表示任意字符
      
    4. in

      filter(Book.name.in_(['Name 1', 'Name 2']))
      # in_的参数也可以是query的查询结果
      filter(Book.name.in_(session.query(Book.name).filter(Book.name.like('%Name%'))))
      
    5. not in

      filter(~Book.name.in_(['Name 1', 'Name 2']))
      
    6. is null

      filter(Book.name == None)
      # 或者是
      filter(Book.name.is_(None))
      
    7. is not null

      filter(User.name != None)
      # 或者是
      filter(User.name.isnot(None))
      
    8. 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()
      
    9. 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)
    

    运行结果如下:

在这里插入图片描述

分析:

  1. 可以在query中使用聚合函数,对数据进行操作
  2. 常见的聚合函数有:
    1. func.count()
      统计记录的数量。
    2. func.avg()
      求平均值。
    3. func.max()
      求最大值。
    4. func.min()
      求最小值。
    5. func.sum()
      求和。

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()

运行结果如下:

在这里插入图片描述

分析:

  1. 使用ForeignKey()用来创建外键,传入表名.字段作为第一个参数,第二个参数传入ondelete='RESTRICT’用来设置外键的约束级别
  2. MySQL中的外键约束有以下几个级别:
    1. RESTRICT
      严格模式,若子表中有父表对应的关联数据,删除父表对应数据,会阻止删除,也是默认项
    2. NO ACTION
      在MySQL中,同RESTRICT。
    3. CASCADE
      级联模式,父表操作后,对应子表关联的数据也进行操作。
    4. SET NULL
      置空模式,父表被操作之后,子表对应的外键字段被置空。

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()

运行结果如下:

在这里插入图片描述

分析:

  1. 两个存在外键约束的表可以使用relationship来创建表关系,参数为关联表模型类名字
  2. 对于存在表关系的数据,提交一个表数据时,另一个表的数据也会自动提交
  3. 存在外键的子表对应多,所以使用主表的关联字段查询的内容为列表

一对一关系

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都差不多。这里不做详细讲解,需要的时候可以百度或者参考官方文档。

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值