9

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

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

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

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

4

1 回答 1

13

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

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 子查询的概念。如果您将我原来的 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
于 2012-12-28T04:03:32.933 回答