python – sqlalchemy以一对多的关系添加孩子

前端之家收集整理的这篇文章主要介绍了python – sqlalchemy以一对多的关系添加孩子前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这是我第一次使用ORM,所以我不知道最好的方法来处理这个.我有一对多的关系,每个父母可以有很多孩子:
  1. class Parent(Base):
  2. __tablename__ = 'Parent'
  3.  
  4. name = Column(String(50))
  5. gid = Column(String(16),primary_key = True)
  6. lastUpdate = Column(DateTime)
  7.  
  8. def __init__(self,name,gid):
  9. self.name = name
  10. self.gid = gid
  11. self.lastUpdate = datetime.datetime.now()
  12.  
  13.  
  14. class Child(Base):
  15. __tablename__ = 'Child'
  16.  
  17. id = Column(Integer,primary_key = True)
  18. loc = Column(String(50))
  19. status = Column(String(50))
  20.  
  21. parent_gid = Column(String(16),ForeignKey('Parent.gid'))
  22.  
  23. parent = relationship("Parent",backref=backref('children'))

现在,通过网络进行更新.当进行更新时,我想更新相应的父行(更新lastUpdate列)并将新的子项行插入数据库.我不知道如何使用ORM.这是我失败的尝试:

  1. engine = create_engine('sqlite+pysqlite:///file.db',module=dbapi2)
  2. Base.Metadata.create_all(engine)
  3. session = sessionmaker(bind=engine)()
  4.  
  5. def addChildren(parent):
  6. p = session.query(Parent).filter(Parent.gid == p1.gid).all()
  7. if len(p) == 0:
  8. session.add(p1)
  9. session.commit()
  10. else:
  11. updateChildren = parent.children[:]
  12. parent.chlidren = []
  13. for c in updateChildren:
  14. c.parent_gid = parent.gid
  15.  
  16. session.add_all(updateChildren)
  17. session.commit()
  18.  
  19. if __name__ == '__main__':
  20.  
  21. #first update from the 'network'
  22. p1 = Parent(name='team1',gid='t1')
  23. p1.children = [Child(loc='x',status='a'),Child(loc='y',status='b')]
  24. addChildren(p1)
  25.  
  26. import time
  27. time.sleep(1)
  28.  
  29. #here comes another network update
  30. p1 = Parent(name='team1',gid='t1')
  31. p1.children = [Child(loc='z',Child(loc='k',status='b')]
  32. #this fails
  33. addChildren(p1)

我最初试图做一个合并,但这导致老的孩子被取消与父母的关联(外部ID被设置为null).用ORM来处理这个问题的最好方法是什么?谢谢

编辑

我想,当更新进入网络时,创建全新的对象并不真正有意义.我应该只是查询相应的父级会话,然后在必要的时候创建新的子项并合并?例如.

  1. def addChildren(pname,pid,cloc,cstat):
  2. p = session.query(Parent).filter(Parent.gid == pid).all()
  3. if len(p) == 0:
  4. p = Parent(pname,pid)
  5. p.children = [Child(loc=cloc,status=cstat)]
  6. session.add(p)
  7. session.commit()
  8. else:
  9. p = p[0]
  10. p.children.append(Child(loc=cloc,status=cstat))
  11. session.merge(p)
  12. session.commit()

解决方法

你是对的 – 你不应该创建同一个父母两次.在添加孩子方面,嗯,你真的只需要添加他们,你不关心现有的…所以你编辑的代码应该做的工作很好.你可以使它更短,更可读:
  1. def addChildren(pname,cstat):
  2. p = session.query(Parent).get(pid) # will give you either Parent or None
  3. if not(p):
  4. p = Parent(pname,pid)
  5. session.add(p)
  6. p.children.append(Child(loc=cloc,status=cstat))
  7. session.commit()

这种方式的缺点是,对于现有的Parent,在添加新的Child并将其保存到数据库之前,所有的Children集合将被加载到内存中.如果是这种情况(每个父母的孩子数量越来越多),那么lazy='noload'可能是有用的:

  1. parent = relationship("Parent",backref=backref('children',lazy='noload'))

这可能会显着提高插入速度,但在这种情况下,对p.children的访问将永远不会从数据库加载现有对象.在这种情况下,定义另一种关系就足够了.在这种情况下,我更喜欢使用Building Query-Enabled Properties,所以最终只能添加一个属性添加对象,另一个属性仅用于查询持久化结果,这些结果通常由系统的不同部分使用.

猜你在找的Python相关文章