Найти - Пользователи
Полная версия: Три выборки из модели в одном шаблоне
Начало » Django » Три выборки из модели в одном шаблоне
1 2
iceberg
День добрый! Хотел поинтересоваться у гуру Django насчёт оптимального решения. Есть одна несложная модель
class AlarmA(models.Model):
    user = models.ForeignKey(User)
    caption = models.CharField(max_length=30)
    alarmdate = models.DateField('Alarm date', blank=True, null=True)
    # other fields

Для каждого пользователя делается выборка, состоящая из всех его личных экземпляров модели (по полю User). Это делается элементарно, но есть одна проблема. В шаблоне нужно выводить список не в одном месте, а в трех, в зависимости от значения поля alarmdate, т.е. фактически разбить весь большоя список на три подсписка (3 группы).
1. Записи с заполненным значением alarmdate, где alarmdate меньше текущей даты.
2. Записи с заполненным значением alarmdate, где alarmdate равны или больше текущей даты.
3. Записи с незаполненным значением alarmdate.

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

Для себя нашёл два варианта решения.

1. Вьюха, произведенная от LstView возвращает список с одной из групп alarmdate (например, только не заполненные). Два других подсписка передаются в рендеринг через дополнительные контекст с помощью get_context_data. В этом случае имеем по сути три выборки во вью, но при обработке контекста каждый подсписок обрабатывается автономно от других.

2. Вьюха возвращает один общий список, но у каждого экземаляра в большом общем списке ставим маркер группы (например с помощью дополнительного поля и метода extra). В этом случае придётся в шаблоне трижды проходить один и тот же цикл, со своим условеым оператором для каждой секции шаблона.

Вопрос такой: какой из этих двух вариантов решения является оптимальным с точки зрения наименьшей нагрузки на сервер? Не знаю, имеет ли значение тип, если что у меня nginx+gunicorn+postgresql? И вообще, может быть напрасно парюсь, а есть решение лучше?
Alen
iceberg
Как я понимаю, при рендеринге нет возможности сравнивать даты с помощью существующих шаблонных фильтров и тегов.

Почему? А unixtime.

iceberg
Alen
Почему? А unixtime.
В шаблоне? Типа сравнить c now? Ну не знаю, что-то никогда не встречал.

В любом случае остается вопрос, что выгоднее: три выборки во вьюхе и три меньших цикла в шаблоне или три цикла в шаблоне по всему здоровому списку каждый?
Singularity
iceberg
выбрать все и отсортировать вручную в память не влезет?

Напиши оба варианта и сравни.
ilnur
я бы делал по 1 варианту. потому что вся логика должна быть во вьюхе, а шаблон должен просто рендерить стрницу, без никакой логики.
FishHook
ilnur
без никакой логики.
Это красиво в теории, но не работает на практике.
Пример: есть страница на сайте, которая отображает объём продаж носков по месяцам.
Таблица в БД простая:
product: ForeignKey(Product)
year: Integer
month: Integer
value: Integer
Страница состоит из таблицы, содержащей из 12 столбцов и одну строку. Какие данные должны быть помещены в контекст?
Наверное, какие-то такие:
context["month_data"] = TotalSales.objects.filter(year=2014, product__name="Sock").order_by("month")
Для того, чтобы нарисовать требуемую таблицу данных достаточно - тупо for.
<table>
<tr>
{% for val in  month_data%}
    <td>{{ val }}</td>
{% endfor %}
</tr>
Вы это сделали, получили гонорар, заказчика всё устраивает. Но через месяц он звонит и говорит: Ильнур, хочу чтобы в каждой ячейке была информация о том, на сколько возросли продажи относительно предыдущего месяца. Ваши действия?
Вариант первый (тот который предполагает Ваш подход): Вы во View вместо простого запроса к БД конструируете нечто такое:
qs = TotalSales.objects.filter(year=2014, product__name="Sock").order_by("month")
res = []
for i, t in enumerate(qs):
    value = t.value
    if i = 0:
         previous = 0
    else:
         previous = res[ i - 1 ]
    increment = (value - previous) if previous else 0   
context["month_data"] = {"value": vaue, "increment": increment}
Соответственно, шаблон Вам тоже нужно переписать.

Вариант второй, представление мы не трогаем, контекст остался тот же самый.
<table>
<tr>
{% for val in  month_data %}
    {% if forloop.counter > 0 %}
        <td>{{ val - month_data[forloop.counter - 1] }}</td>
    {% else %}
        <td>0</td>
    {% endif %}
    <td>{{ val }}</td>
{% endfor %}
</tr>
Что проще и логичней? Да-да-да, я знаю, что в шаблонах Джанги нельзя просто так взять и вычесть одно значение из другого, Джанга рассчитана на верстальщиков, не имеющих понятия об элементарной арифметике. Но Вы то имеете такое понятие, Вам то нахрена подобные извраты? А завтра заказчик опять поменяет ТЗ, скажет “А давай еще сумму по месяцам”, а потом “А давай средний прирост”, “А давай собачий член сбоку нарисуем” …
И каждый раз Вы будете переписывать представление? А зачем? Как с самого начала было достаточно данных для построения страницы, так их по прежнему достаточно.

ilnur
без никакой логики.
Это такая вещь в себе, на которую молятся, которой пытаются безусловно следовать, НО ЗАЧЕМ? Вот не станет мой проект лучше, быстрее и расширяемей, если я выпилю всю логику из шаблонов, ни на капельку не станет. Но геморроя, лично мне, прибавит.

Поэтому jinja2 only.
ilnur
FishHook
полностью с вами согласен. но в данном случаем, я бы сделал так, как я написал.

FishHook
Поэтому jinja2 only.
тогда давайте сразо на мако писать и шаблоны и вьюхи. :)
насколько я знаю, в мако в темплайты сразу можно писать питон код

:)
FishHook
То есть у Вас дихотомия мозга: или следуем заветам MVC до усёра, или кодим в шаблоне на питоне.
Ильнур, так нельзя. Разумных людей отличает способность выбирать инструмент для задачи, взвешивая “pro” и “contra”.
ilnur
придерживаемся мвс, где он мешает или не подходит, пишет по своему
FishHook
ilnur
где он мешает или не подходит, пишет по своему
А людей учите почему то иному
а шаблон должен просто рендерить стрницу, без никакой логики.
категоричненько так.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB