在一对多,或者多对多关系的时候,如果想要获取多的一方这一部分的数据的时候,往往能通过一个属性就可以全部获取了。
如有一个部门,想要这个部门下的所有员工,通过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)()
二、创建模型类(部门表和员工表)
非懒加载
#创建模型类
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:上述第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的下的所有员工信息,会查询出所有的数据
a、上述代码执行print(d1)
:打印sql语句
print(d1)
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
b、执行print(type(d1))
<class 'sqlalchemy.orm.query.Query'>
c、执行print(d1.first())
查询部门编号为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>]
特别注意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()
查询数据:
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)
a、执行print(d1.first())
:查询部门编号为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
c、执行print(type(d1.first().emps))
<class 'sqlalchemy.orm.dynamic.AppenderQuery'>
d、执行以下代码:查询员工表总工资超过6000的员工信息
result=d1.first().emps
res=result.filter(Emp.sal>=6000).all() #查询员工表总工资超过6000的员工信息
print(res)
for i in res:
print(i)
[<__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
添加数据
e1=Emp(emp_name='linux',hire_date='2019-12-01',sal=8000)
result.append(e1)
session.commit()
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/123385.html