Python SQLAlchemy可以做而Django ORM不能做的示例

Python SQLAlchemy可以做而Django ORM不能做的示例,python,sqlalchemy,django-orm,Python,Sqlalchemy,Django Orm,我最近做了很多研究,探讨了将Pyramid与SQLAlchemy结合使用,而不是将当前应用程序保留在Django中。这本身就是一场完整的辩论,但我不是来讨论这个问题的 我想知道的是,为什么人们普遍认为SQLAlchemy比Django ORM更好?我发现,几乎每一个,如果不是每一个的话,比较这两种方法都有利于炼金术。我认为性能是一个很大的问题,因为SQLAlchemy的结构让它更顺利地转换为SQL 但是,我也听说对于更难的任务,Django ORM几乎不可能使用。我想找出这个问题有多大。我一直在

我最近做了很多研究,探讨了将Pyramid与SQLAlchemy结合使用,而不是将当前应用程序保留在Django中。这本身就是一场完整的辩论,但我不是来讨论这个问题的

我想知道的是,为什么人们普遍认为SQLAlchemy比Django ORM更好?我发现,几乎每一个,如果不是每一个的话,比较这两种方法都有利于炼金术。我认为性能是一个很大的问题,因为SQLAlchemy的结构让它更顺利地转换为SQL

但是,我也听说对于更难的任务,Django ORM几乎不可能使用。我想找出这个问题有多大。我一直在阅读切换到SQLAlchemy的原因之一是Django ORM不再适合您的需要

那么,简而言之,是否有人可以提供一个SQLAlchemy可以执行的查询(不必是实际的SQL语法),但Django ORM不可能不添加额外的原始SQL就可以执行

更新

自从我第一次问起,我就注意到这个问题引起了相当多的注意,所以我想多加两分钱

最后我们使用了SQLAlchemy,我必须说我对这个决定很满意

我再次讨论这个问题是为了提供SQLAlchemy的另一个特性,到目前为止,我还无法在Django ORM中复制这个特性。如果有人能举例说明如何做到这一点,我会欣然接受

太长了,读不下去了,比如说你想用一些PostgreSQL函数,比如SimulalId(),它提供了一个模糊的比较(参见:-TL;DR输入两个字符串返回百分之一的相似性)。 我已经使用Django ORM搜索了一些如何做到这一点,除了使用原始sql之外,我没有发现任何其他东西,从他们的文档中可以明显看出:

i、 e

但是,SQLalchemy具有func(),如下所述:


这允许您为任何已定义的sql/postgresql/etc函数生成sql,而不需要原始sql。

这几乎是非构造性的,但我要咬一口

假设我们需要为一些不同的账户保存某些物品的库存。DDL如下:

CREATE TABLE account (
    id serial PRIMARY KEY,
    ...
);

CREATE TABLE item (
    id serial PRIMARY KEY,
    name text NOT NULL,
    ...
);

CREATE TABLE inventory (
    account_id integer NOT NULL REFERENCES account(id),
    item_id integer NOT NULL REFERENCES item(id),
    amount integer NOT NULL DEFAULT 0 CHECK (amount >= 0),
    PRIMARY KEY (account_id, item_id)
);
首先,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中无法用自定义条件表示外部联接。是的,您可以进行两个简单的单独查询,并在Python循环中手动执行join。在这种特殊情况下,性能可能不会受到太大影响。但这不是重点,因为每个查询的结果都可以在应用程序端仅使用basic
SELECT
s进行复制

使用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使基于词典的集合变得非常容易。通过将以下代码添加到
账户
模型中,您可以使与
库存
的关系按原样显示:从项目到其数量的映射

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))
这使您能够编写代码,例如:

account.inventory[item_id] += added_value
透明地插入或更新
库存
表中的条目


复杂的连接、子查询、窗口聚合—Django ORM无法处理这些问题,而不会返回原始SQL。

这应该在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)))

谢谢这正是我想要的。我也担心它是非建设性的,但我的目标是得到一个可靠的例子,大多数在线资源说“SQLAlchemy更好”,但没有提供进一步的细节。COALESCE—“返回列表中的第一个非空值”另一个答案声称它已解决。这个答案也应该编辑吗?
sqlalchemy
不仅仅是ORM。ORM不能很好地处理
asyncio
,但是
sqlalchemy
表达式语言可以很好地处理异步代码。
account.inventory[item_id] += added_value
inventory_amount = Subquery(account.inventory_set.filter(item=OuterRef('pk')).values('amount'))
Item.objects.annotate(inventory_amount=Coalesce(inventory_amount, Value(0)))