суббота, 28 июня 2014 г.

Ловушка сортировки по умолчанию в django.

В отображаемом списке групп объектов присутствуют метрики из связанной модели. Так вот из тысяч объектов вдруг для одной группы объектов метрики стали отображаться неправильно. Причем в ближайшее время ничего не изменялось, что в теории могло бы повлиять на этот функционал.

Как оказалось, виновником такого поведения стала сортировка по умолчанию. Обо всем по порядку.


Пару лет назад в несколько моделей приложения была добавления сортировка по умолчанию.
class Meta:
    ordering = ['-created']

На тот момент операций с этими моделями было очень мало и использование сортировки по умолчанию выглядело вполне оправдано. Шло время, проект усложнялся и усложнялся. В один прекрасный вечер пятницы вылез неожиданный баг о котором уже сказал.

Формирование данных по метрикам для каждого объекта выполнялось так:
class MetricQuerySet(models.query.QuerySet):
    def sum_by(self, f):
        return {
            k: MetricGroup({v['metric']: v['sum'] for v in group})
            for k, group in groupby(
                self.values(f, 'metric').order_by(f).annotate(sum=models.Sum('value')),
                key=lambda datum: datum[f]
            )
        }
Недавно в приложении появилась новая возможность создавать группы объектов копированием. Естественно у всех новых объектов скопированных за одну операцию время создания оказалось одинаковым.

Для функции groupby модуля itertools сортировка передаваемых данных очень важна. Здесь все и случилось.

Django ORM в SQL запросах продолжает использовать сортировку по умолчанию, даже если в конструкции запроса сортировка задана явно, как в нашем случае.

Соответственно все работало пока сортировка по полю 'created' чудесным образом не противоречила сортировке по указанному полю.

Вот такие грабли. Выходит сортировку по умолчанию лучше не использовать или, во всяком случае, все время помнить о таком поведении.

Стоит отметить, что подобное поведение было замечено в django 1.4.13

Комментариев нет:

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