当前位置:   article > 正文

【Flask】ORM高级操作之懒加载_flask orm加载已有表

flask orm加载已有表

在一对多,或者多对多关系的时候,如果想要获取多的一方这一部分的数据的时候,往往能通过一个属性就可以全部获取了。
如有一个部门,想要这个部门下的所有员工,通过user.emp就可以获取所有的。
但有时候我们不想获取所有的数据,如只想获取范围更小的数据,那么这时候我们可以给relationship方法添加属性lazy=‘dynamic’,以后通过user.emp获取到的就不是一个列表,而是一个AppenderQuery对象了。这样就可以对这个对象再进行一层过滤和排序等操作。

一、数据准备:配置数据库、创建数据库引擎、创建基类、创建session

from sqlalchemy import create_engine, Column, Integer, ForeignKey, String, TEXT, Boolean, DATE, DECIMAL
from sqlalchemy.ext.declarative import declarative_base
from datetime import date
from sqlalchemy.orm import sessionmaker,relationship,backref


#配置数据库
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)

#创建基类,所有的模型类继承基类
Base=declarative_base(engine)

#创建session
session=sessionmaker(engine)()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

二、创建模型类(部门表和员工表)

非懒加载

#创建模型类
class Dept(Base):
    __tablename__='t_dept2'
    dept_no=Column(name='dept_no',type_=Integer,primary_key=True,autoincrement=True)
    dept_name=Column(name='dept_name',type_=String(20))
    city=Column(name='city',type_=String(20))

    #代表当前部门下的所有员工列表,这种写法不是最好的,最优的写法只要在一个对象中关联就可以了
    #emp=relationship('Emp') #参数必须是另一个关联模型类的类名


    def __str__(self):
        return f'部门编号:{self.dept_no}部门:{self.dept_name}城市:{self.city}'

class Emp(Base):
    __tablename__='t_emp2'
    emp_no=Column(name='emp_no',type_=Integer,primary_key=True,autoincrement=True)
    emp_name=Column(name='emp_name',type_=String(20))
    hire_date=Column(name='hire_date',type_=DATE)
    sal=Column(name='sal',type_=DECIMAL(10,2))

    #todo 设置外键关联,在从表中增加一个字段,指定这个字段外键的是哪个表的哪个字段就可以了。从表中外键的字段,必须和主表的主键字段类型保持一致。
    dept_no=Column(ForeignKey('t_dept2.dept_no',ondelete='CASCADE'),name='dept_no',type_=Integer)

    #代表员工所属的部门信息,backref:反向关联的属性名
    dept=relationship('Dept',backref=backref('emps'))        #参数必须是另一个关联模型类的类名

    def __str__(self):
        return f'员工编号:{self.emp_no}员工姓名:{self.emp_name}员工入职时间:{self.hire_date}员工薪资:{self.sal}'

#根据模型类建表
#Base.metadata.create_all()
#Base.metadata.drop_all()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

特别注意1:上述第26行代码默认为:lazy=‘select’,表示非懒加载
dept=relationship('Dept',backref=backref('emps',lazy='select'))

三、查询数据

def query():
    d1=session.query(Dept).filter(Dept.dept_no==1)      #查询部门编号为1的部门信息
    print(d1)                                           #sql语句
    print(type(d1))                                     #<class 'sqlalchemy.orm.query.Query'>

    print(d1.first())                                   #查询部门编号为1的部门信息
    print(d1.first().emps)                              #查询部门编号为1的下的所有员工信息,会查询出所有的数据

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

a、上述代码执行print(d1):打印sql语句

print(d1)
  • 1
SELECT t_dept2.dept_no AS t_dept2_dept_no, t_dept2.dept_name AS t_dept2_dept_name, t_dept2.city AS t_dept2_city 
FROM t_dept2 
WHERE t_dept2.dept_no = %(dept_no_1)s
  • 1
  • 2
  • 3

b、执行print(type(d1))

<class 'sqlalchemy.orm.query.Query'>
  • 1

c、执行print(d1.first()) 查询部门编号为1的部门信息

部门编号:1部门:信息部城市:北京
  • 1

d、执行print(d1.first().emps) 查询部门编号为1的下的所有员工信息,会查询出所有的数据

[<__main__.Emp object at 0x00000267DD7877C0>, <__main__.Emp object at 0x00000267DD787AC0>, <__main__.Emp object at 0x00000267DD787820>, <__main__.Emp object at 0x00000267DD78A4C0>]
  • 1

特别注意2:执行d1.first().emps会查询出所有的数据;加入部门表下有100w条数据,会一次性加载出来,因为默认lazy='select,会把所有关联属性的值都会查询出来;影响性能,会造成内存溢出

调试代码可以看出:数据被加载出来了;<class ‘sqlalchemy.orm.query.Query’>:不可以添加的query,由此不可以插入数据
在这里插入图片描述

懒加载
修改上述代码即可

#创建模型类
class Dept(Base):
    __tablename__='t_dept2'
    dept_no=Column(name='dept_no',type_=Integer,primary_key=True,autoincrement=True)
    dept_name=Column(name='dept_name',type_=String(20))
    city=Column(name='city',type_=String(20))

    #代表当前部门下的所有员工列表,这种写法不是最好的,最优的写法只要在一个对象中关联就可以了
    #emp=relationship('Emp') #参数必须是另一个关联模型类的类名


    def __str__(self):
        return f'部门编号:{self.dept_no}部门:{self.dept_name}城市:{self.city}'

class Emp(Base):
    __tablename__='t_emp2'
    emp_no=Column(name='emp_no',type_=Integer,primary_key=True,autoincrement=True)
    emp_name=Column(name='emp_name',type_=String(20))
    hire_date=Column(name='hire_date',type_=DATE)
    sal=Column(name='sal',type_=DECIMAL(10,2))

    #todo 设置外键关联,在从表中增加一个字段,指定这个字段外键的是哪个表的哪个字段就可以了。从表中外键的字段,必须和主表的主键字段类型保持一致。
    dept_no=Column(ForeignKey('t_dept2.dept_no',ondelete='CASCADE'),name='dept_no',type_=Integer)

    #代表员工所属的部门信息,backref:反向关联的属性名,lazy='dynamic:懒加载
    dept=relationship('Dept',backref=backref('emps',lazy='dynamic'))        #参数必须是另一个关联模型类的类名

    def __str__(self):
        return f'员工编号:{self.emp_no}员工姓名:{self.emp_name}员工入职时间:{self.hire_date}员工薪资:{self.sal}'

#根据模型类建表
#Base.metadata.create_all()
#Base.metadata.drop_all()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

查询数据:

def test_lazy():

    d1=session.query(Dept).filter(Dept.dept_no==1)
    print(d1.first())                                   #查询部门编号为1的部门信息
    print(type(d1.first().emps))                        #<class 'sqlalchemy.orm.dynamic.AppenderQuery'>
    print(d1.first().emps)                              #sql语句
    result=d1.first().emps
    res=result.filter(Emp.sal>=6000).all()
    print(res)
    for i in res:
        print(i)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

a、执行print(d1.first()) :查询部门编号为1的部门信息

部门编号:1部门:信息部城市:北京
  • 1

b、执行print(d1.first().emps) :查询部门编号为1下的员工信息,由于懒加载模式,不会立即加载出数据,只有具体操作数据时,才会加载数据

SELECT t_emp2.emp_no AS t_emp2_emp_no, t_emp2.emp_name AS t_emp2_emp_name, t_emp2.hire_date AS t_emp2_hire_date, t_emp2.sal AS t_emp2_sal, t_emp2.dept_no AS t_emp2_dept_no 
FROM t_emp2 
WHERE %(param_1)s = t_emp2.dept_no
  • 1
  • 2
  • 3

c、执行print(type(d1.first().emps))

<class 'sqlalchemy.orm.dynamic.AppenderQuery'>
  • 1

d、执行以下代码:查询员工表总工资超过6000的员工信息

result=d1.first().emps
res=result.filter(Emp.sal>=6000).all()      #查询员工表总工资超过6000的员工信息
print(res)
for i in res:
   print(i)
  • 1
  • 2
  • 3
  • 4
  • 5
[<__main__.Emp object at 0x00000282DE6AC910>, <__main__.Emp object at 0x00000282DE6ACCA0>, <__main__.Emp object at 0x00000282DE6ACC70>]
员工编号:1员工姓名:python员工入职时间:2020-01-01员工薪资:8888.88
员工编号:3员工姓名:javascript员工入职时间:2021-06-01员工薪资:6000.00
员工编号:4员工姓名:jmeter员工入职时间:2022-06-04员工薪资:10000.00
  • 1
  • 2
  • 3
  • 4

添加数据

e1=Emp(emp_name='linux',hire_date='2019-12-01',sal=8000)
result.append(e1)
session.commit()
  • 1
  • 2
  • 3

在这里插入图片描述

调试代码:类型为:AppenderQuery;可以添加的query,由此可以插入数据
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/540417
推荐阅读
相关标签
  

闽ICP备14008679号