Производительность Django (серия 4 частей)
Рекурсивные звонки часто необходимы, когда у вас есть таблица самостоятельных ссылок
Нашим примером сегодня будут элементы и категории, которые пользователь хочет получить подробную информацию о категории элементов к категории root.
Корневая категория > Категория > Подкатегория > категория листьев
#models.py class Category(models.Model): name = models.CharField(max_length=127) parent = models.ForeignKey('self', null=True)
Нам нужно внедрить запрос, который получает путь к категории к корне:
Наивное решение:
def path_to_root_category(category_id): if category_id is None: return [] category = Category.objects.get(pk=category_id) result = path_to_root_category(category.parent_id) result.append(category) return result
path_to_root_category (4)
[<Категория: root>, <категория: категория>, <Категория: подкатегория>, <Категория: Категория листьев>]
Стоимость этой функции составляет 4 запроса (количество узлов на пути) Если у нас есть путь большого количества узлов, это будет так плохо.
Оптимизированное решение:
def path_to_root_category(category_id): query = ''' WITH RECURSIVE parents AS ( SELECT category.*, 0 AS relative_depth FROM category WHERE id = %s UNION ALL SELECT category.*, parents.relative_depth - 1 FROM category,parents WHERE category.id = parents.parent_id ) SELECT id, name, parent_id, relative_depth FROM parents ORDER BY relative_depth; ''' return Category.objects.raw(query, [category_id])
Результат:
Пояснение запроса
Сначала найдите элемент целевой категории и сделайте его первым элементом
родители
установленСледуйте за родителем всех категорий в
родители
установить и добавить их в тот же наборНаконец -то выберите все категории в
родители
Установить упорядоченный по глубине
Производительность Django (серия 4 частей)
Оригинал: “https://dev.to/shawara/django-orm-optimization-tips-4-recursive-query-4on1”