5

ネストされたコメント システムの場合、Commentモデルで次の定義を使用して、ツリー構造を PostgreSQL テーブルに格納しています。

path = sa.Column(ARRAY(sa.Integer))

これにより、コメントのすべての ID が現在のパスに保存されます。したがって、id15 のコメントが 11 と 13 の子である場合、そのパスは になります[11,13,15]

ここで、子コメントを見つけて数えたいと思います。したがって、コメント 11 のすべての子を見つけるために、それ自体を含めて、次のような SQL を生成したいと考えています。

SELECT id, path FROM comments WHERE path[1] = 11;

私のデータベースでは、これはコメント 11 とその子の素敵なセットを喜んで返します。

上記の例で、コメントの子を取得したい場合は、次の SQL を使用できます。

SELECT id, path FROM comments WHERE path[1] = 11 AND path[2] = 13;

この SQL を生成するには、SQLAlchemy をどのように使用すればよいですか?

filter_by()私は多くの成功を収めて、または成功せfilter()ずにハッキングしました...これらのどちらも機能しません:

q = Comment.query.filter(path[1] == 11)
> NameError: name 'path' is not defined

q = Comment.query.filter_by(path[1] = 11)
> SyntaxError: keyword can't be an expression

このクエリ用にカスタム SQL を記述したくないのですが、それが唯一の方法である場合は、どのように構築するのが最適かについての指針を教えてください。

編集 1

SQLAlchemy 0.7 を使用していることを確認するため、このバージョンで (回避して) 動作する回答は非常に役立ちます。

上記のコメントの実装では、ID 番号を正確な位置で見つける必要はなく、任意の位置で見つけることもできることに気付きました。したがって、SQLAlchemy を作成してこのようなものを生成する方法についての入力は良いでしょう:

SELECT id, path FROM comments WHERE 11 = ANY (path);

それは可能ですか?

4

1 に答える 1

5

これは、SQLAlchemy 0.8 (これを書いている時点では beta2) 以降でのみ機能します。

from sqlalchemy.dialects import postgresql

class Comment(Base):
    __tablename__ = 'comments'
    id = Column(Integer, primary_key=True)
    path = Column(ARRAY(Integer))

q = Comment.query.filter(Comment.path[1] == 11)
# This is just to demonstrate how compiled query would look like.
print q.statement.compile(dialect=postgresql.dialect())

出力:

SELECT comments.id, comments.path 
FROM comments 
WHERE comments.path[%(path_1)s] = %(param_1)s

アップデート

最近、Postgres 配列の (および関連する) クエリを作成する方法について、SA メーリング リストで議論がありました。= ANYそこにある例は 0.8 用に書かれていますが、0.7 でもある程度は機能するはずです。= ANYfor 0.7 (テスト済み)の実用的な実装を次に示します。

from sqlalchemy.sql import literal, tuple_

# There's already built-in any() function in Python, we don't want to
# shadow that.
def any_(value, col):
    return literal(value).op('= ANY')(tuple_(col))

q = Comment.query.filter(any_(11, Comment.path))
于 2013-01-14T13:48:54.000 に答える