SqlAlchemy запрашивает глубоко вложенные объекты - PullRequest
0 голосов
/ 01 декабря 2019

Мне нужна помощь с запросом модели, чтобы получить более глубокую связь. Животные это основной стол. Это должно легко загрузить imgs и истории, и это довольно просто. Но AnimalsStories имеет собственные imgs в той же таблице AnimalsImgs. AnimalsImgs имеет imgs для обоих классов Animals и AnimalsStories, и оба класса имеют с ним отношения. Так что я должен иметь возможность загружать всех Animals и их истории в AnimalsStories, а затем из этого класса я могу использовать .img attrubute, который ссылается на AnimalsImgs и содержит imgs для историй. SqlAlchemy говорят, что это возможно с подзапросом. И это. Но только два уровня вниз. 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 как один к одному. Таким образом, с запросом, который я разместил (с подзапросом), это может быть сделано:

    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)

И он печатает все уровни довольно ясно. с присоединением. Мы уверены, что в результате не будет отсутствующих или пустых массивов.

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

1 Ответ

0 голосов
/ 02 декабря 2019

Я не был уверен, какие типы отношений вы хотите смоделировать. Я сделал следующие предположения:

  • Изображение может иметь отношение как к одному животному, так и к нему, а также к одному рассказу или без него.
  • . а также ни к одному или нескольким изображениям
  • Животное может иметь отношение ни к одному, ни к нескольким изображениям, а также ни к одному или нескольким историям

Это приведет к такой модели:

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. Животное a1, которое имеет отношение к изображению ai1 и истории ast1. (но не отношения между историей и изображением.
  2. Животное a2, которое имеет отношение к истории ast2. Ast2 имеет отношение к изображению ai2. Но никаких отношений между ast2 и a2 нет.
  3. Животное a3, которое имеет отношение к истории ast3 и изображению ai3. 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 не связан с историей, а только с животным)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...