Моя библиотека - социальная сеть любителей книг

Интро

Думаю, многие из нас занимались оптимизацие загрузки данных из полей ManyToManyField. Задача для оптимизации проста: есть коллекция объектов с некоторым полем (полями) М2М. Необходимо выбрать данные для поля М2М одним запросом, т.е. не выполнять для каждого объекта из коллекции отдельный запрос, по загрузке однотипных данных.

Думаю, многие для этого писали собственные функции, я же пользовался load_related_m2m, найденной когда-то толи на djbook.ru, толи на сайте Ивана Сагалаева.

И вот при обновлении до Django 1.2.1 при вызове функции load_related_m2m, появилась ошибка: ‘DatabaseWrapper’ object is not callable

Исправляем

Очевидно, произошло это из-за смены интефейсов класса django.db.models.sql.Query. Для возобновления работоспособности необходимо изменить буквально пару строк:

Код


# -*- coding: utf-8 -*-
from django.db.models.sql.constants import LOOKUP_SEP
from django.db.models import sql
from django.db import connection                                               

def load_related_m2m(object_list, field):                                      

    select_fields = ['pk']
    related_field = object_list.model._meta.get_field(field)
    related_model = related_field.rel.to
    cache_name = 'all_%s' % field                                              

    for f in related_model._meta.local_fields:
        select_fields.append('%s%s%s' % (field, LOOKUP_SEP, f.column))         

    query = sql.Query(object_list.model)
    query.add_fields(select_fields)
    query.add_filter(('pk__in', [obj.pk for obj in object_list]))

    related_dict = {}
    cursor = connection.cursor()
    cursor.execute(str(query))

    for row in cursor.fetchall():
        if row[2]:
            related_dict.setdefault(row[0], []).append(related_model(*row[1:]))

    for obj in object_list:
        try:
            setattr(obj, cache_name, related_dict[obj.pk])
        except KeyError:
            setattr(obj, cache_name, [])

    return object_list

З.Ы.

А лето выдалось жаркое. Такое чувство, что в тени +40 )



Комментарии (12) на запись «Django 1.2.1 и load_related_m2m»

  1. Дмитрий MonsterID Icon Дмитрий | 19.07.2010 в 19:08

    Мою функцию допили :)
    Можно ваш вариант добавить на djbook.ru?

  2. Larin MonsterID Icon Larin | 20.07.2010 в 10:10

    Дмитрий, добрый день!

    Т.е. начальный вариант этой функции появился на djbook и вы автор? Это что бы мне в тексте статьи поправить авторство )

    Можно ваш вариант добавить на djbook.ru?

    Конечно, можно! Мне будет приятно знать, что мой patch пригодился кому-то еще )

  3. Дмитрий MonsterID Icon Дмитрий | 20.07.2010 в 11:00

    Эту тему на форуме я и создал :) Попрошу что бы на djbook.ru добавили, но это будет когда у хозяина djbook время найдеться. Еще писал подгрузку связей через GenericForeignKey и ForeignKey с null=True.

  4. Larin MonsterID Icon Larin | 20.07.2010 в 11:06

    Еще писал подгрузку связей через GenericForeignKey и ForeignKey с null=True.

    Не помню такого ) Поделитесь ссылочкой? )

  5. Дмитрий MonsterID Icon Дмитрий | 20.07.2010 в 19:11

    Изволил написать статью :)
    Вот линк.
    На djbook добавили линк на вашу статью.

  6. Lost MonsterID Icon Lost | 19.08.2010 в 18:03

    Да толку, все равно не работает, хоть и ошибок не выдает ((

  7. Дмитрий MonsterID Icon Дмитрий | 19.08.2010 в 18:10

    Если выводили в шаблоне, попробуйте во вьюхе. Шаблон “глотает” часть ошибок.

  8. Lost MonsterID Icon Lost | 19.08.2010 в 18:43

    Пардон, работает - забыл сменить .field.all() на .all_field

    Спасибо большое. Еще бы обратную функцию для .field_set - было бы вообще здорово :)

  9. Larin MonsterID Icon Larin | 19.08.2010 в 20:34

    ИМХО, методам типа “field_set” все же не место в шаблонах, лучше оставить их контроллерам.
    Чем “тупее” шаблон, тем лучше. Тем легче делать редизайны и переносить код от проекта к проекту.

  10. Lost MonsterID Icon Lost | 20.08.2010 в 00:20

    А вто вообще про шаблон говорит? Мне .field_set нужен в вьюхе.

  11. Larin MonsterID Icon Larin | 20.08.2010 в 10:35

    @Lost

    А вто вообще про шаблон говорит? Мне .field_set нужен в вьюхе.

    Тогда немного не понимаю Вашу проблему… что именно не получается? Пример в студию!

  12. Lost MonsterID Icon Lost | 20.08.2010 в 11:41

    К примеру, есть модель:

    class Foo(modelsModel):
         parent = models.ManyToManyField("self", symmetrical = False, null = True, blank = True)

    Собственно, как найти всех родителей категории понятно:

    result = load_related_m2m (Foo.objects.all(), 'parent')

    А вот бы еще так детей заранее загрузить (здесь Foo.foo_set.all() ) одим запросом.

Оставить комментарий


Copyright, 1983 – 2010