SqlAlchemy查询深层嵌套对象

时间:2019-12-01 20:23:55

标签: python sqlalchemy nested

我需要有关查询模型的帮助以获得更深入的了解。 动物是主表。它应该轻松加载img和故事,并且非常简单。但是AnimalsStories在同一AnimalsImgs表中具有自己的img。 AnimalsImgs都具有Animals和AnimalsStories类的img,并且这两个类都具有关系。 因此,我应该能够将所有Animals及其故事加载到AnimalsStories中,然后从该类中,我应该可以使用.img attrubute,它与AnimalsImgs相关,并包含故事的img。 SqlAlchemy说它可以与subqueryload一起使用。是的。但是只有两个级别下降。 AnimalsStories.img永远不会加载。

class Animals(db.Model):
    __tablename__ = 'animals'
    id = db.Column(db.BigInteger, primary_key=True)
    imgs = db.relationship("AnimalsImgs", backref=db.backref('animals',lazy=False))
    stories= db.relationship("AnimalsStories",lazy='joined')

class AnimalsImgs(db.Model):
    __tablename__ = 'animals_imgs'
    id = db.Column(db.BigInteger, primary_key=True,autoincrement='auto')
    id_animal = db.Column(db.BigInteger, db.ForeignKey('animals.id'),nullable=False)

class AnimalsStories(db.Model):
    __tablename__='animals_stories'
    id = db.Column(db.BigInteger, primary_key=True)
    id_animal= db.Column(db.BigInteger,db.ForeignKey('animals.id'), nullable=False)
    id_animal_img = db.Column(db.BigInteger,db.ForeignKey('animals_imgs.id'))
    img=db.relationship("AnimalsImgs", uselist=False)

我尝试过这样的事情:

    query = Animals.query.options(subqueryload(Animals.stories).subqueryload(AnimalsStories.img))
    result = query.all()
    print(result)
    for res in result:
        print(res.rescue.img)

并以“ AttributeError:'InstrumentedList'对象没有属性'img'结尾” 查询更深的对象应该非常简单。我认为问题出在模型结构中。

编辑#1 我已经解决了。这并不难。 动物对故事的引用是一对多的。故事以一对一的形式呈现给Imgs。因此,通过我发布的查询(带有subqueryload),可以通过以下方式完成:

    query = Animals.query.options(subqueryload(Animals.stories).subqueryload(AnimalsStories.img))
    result = query.all()

    print(result)
    for res in result:
        print(res.stories)
        for r in res.stories: # stories appears as array so they are iterable
            print(r.img)

它可以清晰地打印所有级别。

使用join也可以完成甚至更好。我们确保结果没有任何缺失或空数组。

 query = Animals.query.join(AnimalsStories).join(AnimalsImgs) 

1 个答案:

答案 0 :(得分:0)

我不确定要建模的关系类型。我做了以下假设:

  • 图像可以与一个或没有动物有关,也可以与一个或没有故事有关
  • 一个故事与一只动物有关系,与一个或多个图像都没有关系
  • 动物与一个或多个图像,一个或多个故事都没有关系

这将导致这样的模型:

class Animals(db.Model):
  __tablename__ = 'animals'
  id = db.Column(db.Integer, primary_key=True)
  imgs = db.relationship("AnimalsImgs", backref=db.backref('animals'),lazy=True)
  stories= db.relationship("AnimalsStories", backref=db.backref('animals'), 
    lazy=True)

class AnimalsImgs(db.Model):
  __tablename__ = 'animals_imgs'
  id = db.Column(db.Integer, primary_key=True)
  id_animal = db.Column(db.Integer, db.ForeignKey('animals.id'),nullable=True)
  id_animal_story = 
     db.Column(db.Integer,db.ForeignKey('animals_stories.id'),nullable=True)

class AnimalsStories(db.Model):
  __tablename__='animals_stories'
  id = db.Column(db.Integer, primary_key=True)
  id_animal= db.Column(db.Integer,db.ForeignKey('animals.id'), nullable=False)
  imgs=db.relationship("AnimalsImgs", backref=db.backref('stories'),lazy=True)

现在,我添加了以下场景:

  1. 与图像ai1和故事ast1相关的动物a1。 (但不是故事和图片之间的关系。
  2. 与故事ast2有关的动物a2。 Ast2与图像ai2有关系。但是ast2和a2之间没有关系。
  3. 与故事ast3和图像AI3有关系的动物a3。 ai3与ast3也有关系。

代码示例如下:

  a1 = Animals()
  a2 = Animals()
  a3 = Animals ()
  a4 = Animals ()
  db.session.add(a1)
  db.session.add(a2)    
  db.session.add(a3)
  db.session.add(a4)
  ai1 = AnimalsImgs(animals = a1)
  db.session.add(ai1)
  ast1 = AnimalsStories(animals = a1)
  db.session.add(ast1)       
  ast2 = AnimalsStories(animals = a2)
  db.session.add(ast2)    
  ai2 = AnimalsImgs(stories = ast2)
  db.session.add(ai2)    
  ast3 = AnimalsStories(animals = a3)
  db.session.add(ast3)  
  ai3 = AnimalsImgs(animals = a3, stories = ast3)
  db.session.add(ai3)

如果要查询与故事相关的所有图像,可以使用:

  animalimages_ofallstories_ofalanimals = 
      AnimalsImgs.query.join(AnimalsStories).join(Animals).all()

您将得到图像ai2和ai3。 (ai1与故事无关,而仅与动物有关)

相关问题