Оптимизированный способ получения родителей только с последним ребенком, используя Django ORM - PullRequest
6 голосов
/ 25 декабря 2010

Мы хотим получить родительского ребенка таким образом, чтобы он дал мне 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 ]

3 голосов
/ 26 декабря 2010

Вы можете прибегнуть к сырому SQL, и ваш запрос выглядит нормально (просто отсутствует "order by 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 - Анекдот для оптимизации ".

0 голосов
/ 27 декабря 2010

Если вы получаете предметы для каждой категории, вам нужно будет поразить базу данных для каждой категории один раз, поэтому лучше сделать это наоборот и использовать 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, если делать это такспособ!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...