【问题标题】:SQLAlchemy conversion of Django annotateDjango annotate 的 SQLAlchemy 转换
【发布时间】:2012-12-12 13:06:07
【问题描述】:

我在 Django 模型管理器中有以下注释,我想将其转换为 SQLAlchemy ORM 查询:

annotations = {
        'review_count' : Count("cookbookreview", distinct=True), 
        'rating' : Avg("cookbookreview__rating")
    }
return self.model.objects.annotate(**annotations)

我基本上需要的是查询中的每个模型对象都将review_countrating 作为初始查询的一部分附加到它们。我相信我可以使用column_property,但我想避免在对象上使用这种类型的“计算属性”,因为我不希望在访问属性时为每个对象完成属性(昂贵的查找)模板。

解决这个问题的正确方法是什么?提前致谢。

【问题讨论】:

  • 恕我直言,Django 注释和聚合是相当不一致的 hack。 SQLAlchemy 比 Django ORM 强大得多,基本上,您以可重用和参数化的方式拥有 SQL 的全部功能。
  • 谢谢,但是这里Django ORM聚合/注释的问题需要在SQLAlchemy中解决。由于它非常强大,我认为这种类型的查询可以相对轻松地完成。但我无法弄清楚如何。
  • 您可以使用 SqlSoup 映射任何 sqlalchemy.sql.select。
  • 如果不是计算属性,它在 Django 中如何工作?

标签: python django sqlalchemy


【解决方案1】:

因此,为了解决此问题的其他人的完整性和实用性,我提出以下解决方案(这可能是也可能不是解决此问题的最佳方法)

sq_reviews = db_session.query(CookbookReview.cookbook_id, 
    func.avg(CookbookReview.rating).label('rating'),\
    func.count('*').label('review_count')).\
    group_by(CookbookReview.cookbook_id).subquery()

object_list = db_session.query(
    Cookbook, sq_reviews.c.rating, sq_reviews.c.review_count).\
    outerjoin(sq_reviews, Cookbook.id==sq_reviews.c.cookbook_id).\
    order_by(Cookbook.name).limit(20)

这里的关键是SQLAlchemy subqueries 的概念。如果您将我原来的 Django 查询中的每个注释都视为一个子查询,那么这个概念就更容易理解了。还值得注意的是,这个查询非常快——比它(更简洁/神奇)Django 对应的查询要快许多数量级。希望这可以帮助其他对这个特定的 Django/SQLAlchemy 查询模拟感到好奇的人。

还请记住,您需要自己执行 ORM 对象的实际注释。在将对象列表发送到模板之前调用这样一个简单的函数就足够了:

def process(query):
    for obj, rating, review_count in query:
        obj.rating = rating
        obj.review_count = review_count
        yield obj

【讨论】:

猜你喜欢
  • 2011-05-02
  • 2021-01-30
  • 2014-05-18
  • 2017-01-15
  • 2016-10-31
  • 2018-09-22
  • 2021-11-28
  • 1970-01-01
  • 2014-10-12
相关资源
最近更新 更多