简体   繁体   English

SQLAlchemy M2M关系查询

[英]SQLAlchemy M2M relationship query

I have the following Models, and I'm trying to list all the latest DocumentVersions that have a group in the groups of a User. 我有以下模型,并且我试图列出在用户组中具有组的所有最新DocumentVersions。

class User(Base, BaseModel):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    email = Column(Unicode(EMAIL_LENGTH), unique=True, nullable=False)
    full_name = Column(Unicode(FULL_NAME_LENGTH), nullable=False)
    deleted = Column(Boolean, nullable=False, default=False)

    document_versions = relationship(
        'DocumentVersion', 
        backref="author")


class Group(Base, BaseModel):
    __tablename__ = 'groups'
    __table_args__ = (UniqueConstraint('name','company_id'),)
    id = Column(Integer, primary_key=True)
    name = Column(Unicode(60), nullable=False)
    deleted = Column(Boolean, nullable=False, default=False)

    # Companies have many groups
    company_id = Column(
            Integer,
            ForeignKey('companies.id'),
            nullable=False)
    roles = relationship("Role",
            primaryjoin="Group.id==Role.group_id",
            backref="group")
    users = relationship("User",
            secondary=group_user,
            backref="groups")

document_version_group = Table(
        "document_version_groups",
        Base.metadata,
        Column('group_id', Integer, ForeignKey('groups.id')),
        Column('document_version_id', Integer, ForeignKey('document_versions.id')))

class DocumentVersion(Base, BaseModel):
    __tablename__ = 'document_versions'
    id = Column(Integer, primary_key=True)
    document_id = Column(
            Integer,
            ForeignKey('documents.id'),
            nullable=False)

    author_id = Column(
            Integer,
            ForeignKey('users.id'),
            nullable=False)
    groups = relationship(
            "Group",
            secondary=document_version_group,
            lazy='dynamic', # This is newly added just now
            backref="document_versions")
    status = Column(
            Enum(
                "draft",
                "review",
                "approval",
                "declined",
                "approved",
                name="status"),
            default="draft",
            nullable=False)

I have tried the following with no luck (note the document_version returned with zero groups) 我没有运气尝试过以下内容(请注意document_version返回的组数为零)

>>> docs = session.query(DocumentVersion).filter(Document.company == user.company).filter(Group.id.in_([g.id for g in user.groups])).all()

2012-08-31 15:14:19,651 INFO  [sqlalchemy.engine.base.Engine][MainThread] SELECT document_versions.id AS document_versions_id, document_versions.document_id AS document_versions_document_id, document_versions.document_current_draft_id AS document_versions_document_current_draft_id, document_versions.document_current_active_id AS document_versions_document_current_active_id, document_versions.author_id AS document_versions_author_id, document_versions.status AS document_versions_status, document_versions.major_version AS document_versions_major_version, document_versions.minor_version AS document_versions_minor_version 
FROM document_versions, documents, groups 
WHERE %(param_1)s = documents.company_id AND groups.id IN (%(id_1)s)
2012-08-31 15:14:19,651 INFO  [sqlalchemy.engine.base.Engine][MainThread] {'id_1': 1, 'param_1': 1}

>>> [d.groups.all() for d in docs]

2012-08-31 15:15:29,996 INFO  [sqlalchemy.engine.base.Engine][MainThread] SELECT groups.id AS groups_id, groups.name AS groups_name, groups.deleted AS groups_deleted, groups.company_id AS groups_company_id 
FROM groups, document_version_groups 
WHERE %(param_1)s = document_version_groups.document_version_id AND groups.id = document_version_groups.group_id
2012-08-31 15:15:29,996 INFO  [sqlalchemy.engine.base.Engine][MainThread] {'param_1': 1}
2012-08-31 15:15:29,998 INFO  [sqlalchemy.engine.base.Engine][MainThread] SELECT groups.id     AS groups_id, groups.name AS groups_name, groups.deleted AS groups_deleted, groups.company_id AS groups_company_id 
FROM groups, document_version_groups 
WHERE %(param_1)s = document_version_groups.document_version_id AND groups.id = document_version_groups.group_id
2012-08-31 15:15:29,998 INFO  [sqlalchemy.engine.base.Engine][MainThread] {'param_1': 2}
[[], [<project.models.Group object at 0x27ead50>]]

Assuming this SQL gives the correct result: 假设此SQL给出正确的结果:

SELECT *
FROM document_versions
WHERE
    EXISTS (
        SELECT 1
        FROM documents
        WHERE
            document_versions.document_id = documents.id
            AND documents.company_id = :company_id
    )
    AND EXISTS (
        SELECT 1
        FROM document_version_groups
        WHERE
            document_versions.id = document_version_groups.document_version_id
            AND document_version_groups.group_id IN :group_ids
    )

then the following SQLAlchemy expression should work: 那么以下SQLAlchemy表达式应该起作用:

session.query(DocumentVersion).filter(and_(
    DocumentVersion.document.has(compay=user.company),
    DocumentVersion.groups.any(
        Group.id.in_([g.id for g in user.groups])
    ),
)).all()

Note the explicit use of the relationship properties DocumentVersion.document and DocumentVersion.groups . 请注意关系属性DocumentVersion.documentDocumentVersion.groups的显式使用。 Without them, the query will just consist of a bunch of unrelated tables, thus giving you the false positive result. 没有它们,查询将仅由一堆不相关的表组成,从而给您带来假阳性结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM