使用django ORM优化获取只有最新孩子的父母的方式

时间:2010-12-25 07:56:39

标签: python mysql django sqlite django-models

我们希望以这样一种方式获取父子,它给了我最近的10个父母,每个父母只有一个最新的儿童记录。

例如:

Category
- id
- name
- created_date

Item
- id
- name
- category
- created_date

使用上面指定的模型结构,我想获取最新的10个类别以及每个类别的最新子项。

只有一个查询到服务器我想访问所有数据。

Category1.name, Category1.id, LatestItemForCat1.name, LatestItem1ForCat1.created_date
Category2.name, Category2.id, LatestItemForCat2.name, LatestItem1ForCat2.created_date
Category3.name, Category3.id, LatestItemForCat3.name, LatestItem1ForCat3.created_date

使用django ORM实现此目的的最佳方法是什么。

这可以通过以下sql查询获得。我更愿意使用django ORM来解决这个问题。或者更好的SQL查询。

select c.name, c.id, i.name, i.created_date
from
    category c
inner join
    item i
on c.id = i.category_id
where i.id = (select id from item order by created_date desc limit 0,1)
limit 10

2 个答案:

答案 0 :(得分:3)

您可以使用原始SQL,并且您的查询看起来很好(在最终限制之前只缺少“c.created_date desc的顺序”。

原始SQL解决方案中的子查询并没有比返回类别模型中的最后10个条目的方法好得多,类似于此(未经测试的)样本:

class Category(models.Model):
    ...
    def last10items(self):
        return self.item_set.order_by('-created_date')[:10]

我们最多谈论100条记录,我不担心效率,因为后续查询就像是要点击缓存(有几层缓存:django,数据库和操作系统)。这样,您可以传递最后10个类别并从模板中调用last10items:

{% for category in categories %}
  ...
  {% for item in category.last10items %}
      ...

我确信有些混蛋会因为这样说而拒绝我:除非你需要,否则不要试图优化某些东西。在许多情况下,我感到惊讶的是,在对代码进行分析之前,我对一种方法的效率有多么错误。阅读“Python Patterns - An Optimization Anecdote”。

答案 1 :(得分:0)

如果您获得每个类别的项目,则必须为每个类别访问一次数据库,因此最好以相反的方式执行此操作并使用select_related来获取类别属于没有额外命中的项目:

items = Item.objects.order_by('-category__created_date', '-created_date').select_related()
i = 0
cat = None
for item in items:
    if item.category != cat:
        print "%s: %s" % (item.category, item)
        cat = item.category
        i += 1
    if i == 10:
        break    

我添加了一个带有计数器的for循环,只显示10个类别和一个项目,我不认为如果这样做就可以通过ORM限制它!