2013-08-13 21 views
59

最近、SQLAlchemyでPyramidを使用し、Djangoで現在のアプリケーションを使用することについて多くの研究を行ってきました。それだけで議論全体ですが、私はそれについて議論するつもりはありません。SQLAlchemyができることの例Django ORMはできません

私が知りたいことは、SQLAlchemyが普遍的にDjango ORMよりも優れていると考えられる理由です。ほとんどの場合、すべてではないにしても、私はSQLAlchemyの2つの好意を比較しました。私はSQLAlchemyの構造がよりスムーズにSQLに変換できるので、パフォーマンスは大きなものだと思います。

しかし、難しい作業では、Django ORMはほとんど使えないと聞いています。私はこの問題のどれくらいの巨大なものがあるのか​​を明らかにする。私はSQLAlchemyに切り替える理由の1つを読んできました.Django ORMがあなたのニーズに合っていなくなったときです。

つまり、SQLAlchemyが実行できるクエリ(実際のSQL構文である必要はありません)を提供することができますが、Django ORMは追加の未加工SQLを追加することなく実行できますか?

更新

私は私が最初に尋ねたので、かなりの注目を集めてこの問題に気付いてきたので、私は私の余分な2セントでスローにしたいと思います。

最終的にSQLAlchemyを使用しましたが、私はその決定に満足していると言わなければなりません。

これまで、私はDjango ORMで複製できなかったSQLAlchemyの追加機能を提供するために、この問題を再検討しています。誰かがこれを行う方法の例を提供できるなら、私は喜んで私の言葉を食べるでしょう。

たとえば、similarity()のような、あいまいな比較を提供するpostgresql関数を使用したいとしましょう(Finding similar strings with PostgreSQL quickly-tl; dr入力2文字列がパーセント類似性を返す参照)。

Django ORMを使用してこれを行う方法についていくつかの検索を行い、raw sqlをドキュメント以外のものとして見つけました。そのドキュメントからは明らかです:https://docs.djangoproject.com/en/dev/topics/db/sql/。ここで説明するように

Model.objects.raw('SELECT * FROM app_model ORDER BY \ 
similarity(name, %s) DESC;', [input_name]) 

SQLAlchemyのすなわち

が、しかし、)(FUNCを持っていますhttp://docs.sqlalchemy.org/en/latest/core/sqlelement.html#sqlalchemy.sql.expression.func

from sqlalchemy import desc, func 
session.query(Model).order_by(func.similarity(Model.name, input_name)) 

これは、あなたは、任意の定義されたSQL/postgresqlのは/ etc機能のためのSQLを生成することを可能にしていませんraw SQLが必要です。

+0

https://docs.djangoproject.com/en/1.11/ref/models/expressions/#func-expressions –

答えて

48

これは危険で建設的でないことに近いですが、私は噛んでしまいます。

いくつかのアイテムのインベントリを、さまざまな種類のアカウント、たとえばアカウントとする必要があるとします。まず、Django ORMは複合主キーでは動作しません。はい、サロゲートキーと一意性制約はいつでも追加できますが、これは実際に必要とする列と索引です。少数の列を持つ大きな表の場合、これは顕著なサイズとパフォーマンスのオーバーヘッドを追加します。また、ORMは一般に、プライマリキー以外のものを使用したアイデンティティマッピングに問題があります。

ここでは、指定された勘定科目のインベントリの各アイテムにその数量を添えてクエリを行い、量が0に設定されていないすべてのアイテムを含めるとします。対応するSQL:

SELECT item.id, item.name, ..., coalesce(inventory.amount, 0) AS amount 
    FROM item LEFT OUTER JOIN inventory 
     ON item.id = inventory.item_id AND inventory.team_id = ? 
    ORDER BY amount DESC; 

Django ORMでカスタム条件で外部結合を表現する方法はありません。はい、あなたは2つの簡単な別のクエリを作成し、Pythonループで手で結合を実行できます。この特定のケースでは、パフォーマンスはおそらく多くの影響を受けません。しかし、これは、のクエリの結果が、基本的なSELECTだけを使用してアプリケーション側で再現できるため、要点の横にあります。 SQLAlchemyので

:サイドノートとして

class Account(Base): 
    __tablename__ = 'account' 
    id = Column(Integer, primary_key=True) 
    ... 

class Item(Base): 
    __tablename__ = 'item' 
    id = Column(Integer, primary_key=True) 
    name = Column(String, nullable=False) 
    ... 

class Inventory(Base): 
    __tablename__ = 'inventory' 
    account_id = Column(Integer, ForeignKey('account.id'), primary_key=True, 
      nullable=False) 
    account = relationship(Account) 
    item_id = Column(Integer, ForeignKey('item.id'), primary_key=True, 
      nullable=False) 
    item = relationship(Item) 
    amount = Column(Integer, CheckConstraint('amount >= 0'), nullable=False, 
      default=0) 

account = session.query(Account).get(some_id) 
result = (session 
    .query(Item, func.coalesce(Inventory.amount, 0).label('amount')) 
    .outerjoin(Inventory, 
     and_(Item.id==Inventory.item_id, Inventory.account==account)) 
    .order_by(desc('amount')) 
    .all()) 

、SQLAlchemyのは、辞書ベースのコレクションは非常に簡単になります。 Accountモデルに次のコードを追加すると、Inventoryとの関係は、商品と数量のマッピングとして現れます。

items = relationship('Inventory', 
    collection_class=attribute_mapped_collection('item_id')) 
inventory = association_proxy('items', 'amount', 
    creator=lambda k, v: Inventory(item_id=k, amount=v)) 

これは、次のようなコードを書くことができます:透過的inventoryテーブルのエントリを挿入したり更新し

account.inventory[item_id] += added_value 

を。

複雑な結合、サブクエリ、ウィンドウ集約 - Django ORMは、未処理のSQLに落ちることなく、その処理に失敗します。

+1

感謝を!これはまさに私が探していたものです。私はそれが非建設的であることを心配していましたが、私の目標は、ほとんどのオンラインリソースが "SQLAlchemyが優れている"とし、詳細を提供しない、堅実な例を得ることでした。 – limasxgoesto0

2

これは、Djangoの1.11に動作するはずです:

inventory_amount = Subquery(account.inventory_set.filter(item=OuterRef('pk')).values('amount')) 
Item.objects.annotate(inventory_amount=Coalesce(inventory_amount, Value(0))) 
関連する問題