SQLAlchemy находят только родителей, которые содержат указанные c дочерние элементы - PullRequest
0 голосов
/ 27 января 2020

У меня есть следующие модели многие-ко-многим:


class Association(db.Model):
    parent_id = db.Column(db.Integer, db.ForeignKey(
        'parent.id'), primary_key=True)
    child_id = db.Column(db.Integer, db.ForeignKey(
        'child.id'), primary_key=True)
    child = db.relationship("Child", back_populates="parents")
    parent = db.relationship("Parent", back_populates="children")


class Parent(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    children = db.relationship("Association", back_populates='parent', 
                               lazy='dynamic', cascade="save-update, merge, delete, delete-orphan")

class Child(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    parents = db.relationship("Association", back_populates='child', 
                              lazy='dynamic', cascade="save-update, merge, delete, delete-orphan")

Как получить список всех родителей с точными идентификаторами детей в списке (пример: [5,6]) и без дополнительных идентификаторы

Ответы [ 2 ]

1 голос
/ 13 февраля 2020

Я решил эту проблему, используя следующий код:

ids = [c1, c2, c3]
q1 = Parent.query.filter(Parent.children.any(
Association.child_id == c1)).filter(Parent.children.any(Association.child_id == c2))
.filter(Parent.children.any(Association.child_id == c3))
.filter(~Parent.children.any(Association.child_id.notin_(ids)))
.all()

Но я почти уверен, что должны быть лучшие способы сделать это.

1 голос
/ 31 января 2020

Если вы определили дочерние идентификаторы в подзапросе, вы можете выполнить левое соединение из таблицы сопоставлений с этим подзапросом и проверить, что счетчик правильный:

from sqlalchemy import func, and_

Values = [1 ,3]
childcount = len(Values)
childsquery = db.session.query(Child).filter(Child.id.in_(Values)).subquery()             
resultparents = db.session.query(Association.parent_id).outerjoin(childsquery).group_by(Association.parent_id).having(and_(func.count(Association.parent_id) == childcount, func.count(childsquery.c.id) ==  childcount))

Примечание: я думаю, что ваша модель нуждается быть исправленным:

class Parent(db.Model):
   id = db.Column(db.Integer, primary_key=True)
   children = db.relationship("Association", back_populates='parent', 
            lazy='dynamic', cascade="save-update, merge, delete, delete-orphan")

class Child(db.Model):
   id = db.Column(db.Integer, primary_key=True)
   parents = db.relationship("Association", back_populates='child', 
                          lazy='dynamic', cascade="save-update, merge, delete, delete orphan")
...