2

次のモデルがあり、ユーザーのグループにグループを持つ最新の DocumentVersion をすべてリストしようとしています。

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)

次のことを試してみましたが、うまくいきませんでした (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>]]
4

1 に答える 1

1

この 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
    )

次に、次の 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()

関係プロパティDocumentVersion.documentとが明示的に使用されていることに注意してくださいDocumentVersion.groups。それらがないと、クエリは関連のない一連のテーブルで構成されるだけになり、誤検知の結果が得られます。

于 2012-09-03T04:12:31.900 に答える