SQLAlchemy Join Query 得到的不同数据行相同数据是同一个实例

在开发的时候遇到了一个很大的坑(还是因为是我不了解 SQLAlchemy 吧?), 记录一下免得往后再踩...

事情是这样的, 有三张表, 快速地模拟一下表结构:

student表
|------+--------+----------+--------------|
|  id  +  name  +  gender  +  deleted_at  |
|------+--------+----------+--------------|

course表
|------+---------+--------------+--------------|
|  id  +  title  +  teacher_id  +  deleted_at  |
|------+---------+--------------+--------------|

student_course_rel表
|------+--------------+-------------+--------------|
|  id  |  student_id  +  course_id  +  deleted_at  |
|------+--------------+-------------+--------------|

复制代码

这里模拟了一个场景需求, 需要列出某位老师所教授的不同课程的学生列表, 并且要支持全量更新(更新的时候传入的列表为全部学生列表(新增和删除)) 这个时候我要 Join 三张表, 并且同一个学生对应的不同课程的 rel id 也得记录, 这样我就可以知道那些是新增的那些是删除的. 也就是说, 我需要将用户和课程的 rel id 进行绑定. 所以, 我就用这条语句进行 Query:

teacher_id = 'teacher_id'
query_result = db.session.query(Course, Student, StudentCourseRel)\
    .join(StudentCourseRel, Course.id == StudentCourseRel.course_id)\
    .join(Student, StudentCourseRel.student_id == Student.id)\
    .filter(Course.teacher_id == teacher_id, Course.deleted_at.is_(None),
            Student.deleted_at.is_(None), StudentCourseRel.deleted_at.is_(None))\
    .all()
# query 出来的结果大致是这样的
[(course_a, stu_1, rel_1), (course_a, stu_2, rel_2), (course_b, stu_1, rel_3), (course_c, stu_3, rel_4)]
复制代码

这个时候, query 出来的结果确实是我想要的, 每个用户每个课程都会有一条记录. 列表没有任何问题. 但是在更新的时候就出 bug 了.
问题就出在student, course, rel_id绑定这一步用户. 和课程关系的绑定我是遍历数据列表, 并且将 rel id 作为 student 的一个属性.

# 处理数据
result = set()
for item in query_result:
    course, student, rel = item
    if course not in result:
        course.students = []
        result.add(container)
    user.rel_id = rel.id
    course.users.append(user)
return result
复制代码

就上例而言, SQLAlchemy 得到的数据中, course_a 所对应的 stu_1 和 course_b 所对应的 stu_1 是同一个实例, 也就是说在遍历并且进行赋值 rel_id 的时候, 后项会直接覆盖前项, 所以会造成数据的混乱.

这里就暴露出来一个点, 也就是说 SQLAlchemy 在处理 Join 后得到的同样数据是采用 同一个实例 对不同数据行进行拼接.

转载于:https://juejin.im/post/5c10ad9f6fb9a049fb43845e

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值