В Джанго как показать список объектов по годам - PullRequest
1 голос
/ 20 августа 2009

У меня есть тезисы моделей:

class Year(models.Model):
    name = models.CharField(max_length=15)
    date = models.DateField()

class Period(models.Model):
    name = models.CharField(max_length=15)
    date = models.DateField()

class Notice(models.Model):
    year = models.ForeignKey(Year)
    period = models.ForeignKey(Period, blank=True, null=True)
    text = models.TextField()
    order = models.PositiveSmallIntegerField(default=1)

И, на мой взгляд, я хотел бы показать все уведомления, упорядоченные по годам и периодам, но я не хочу повторять год и / или период для уведомления, если они совпадают с предыдущими. Я хотел бы получить такой результат:

1932-1940
Середина лета

  • Текст Lorem ipsum из уведомления 1 ...

  • Текст Lorem ipsum из уведомления 2 ...

Сентябрь

  • Текст Lorem ipsum из уведомления 3 ...

1950
Январь

  • Текст Lorem ipsum из уведомления 4 ...

и т.д.

Я нашел решение, перебрав все строки для создания вложенных списков, например:

years = [('1932-1940', [
                        ('Mid-summer', [Notice1, Notice2]),
                        ('September',  [Notice3])
                       ]),
           ('1950',    [
                        ('January', [Notice4])
                       ])
         ]

Вот код в представлении:

years = []
year = []
period = []
prev_year = ''
prev_period = ''
for notice in Notice.objects.all():
    if notice.year != prev_year:
        prev_year = notice.year
        year = []
        years.append((prev_year.name, year))
        prev_period = ''
    if notice.periode != prev_period:
        prev_period = notice.periode
        period = []
        if prev_period:
            name = prev_period.name
        else:
            name = None
        year.append((name, period))
    period.append(notice)

Но это медленно и не элегантно. Какой хороший способ сделать это?

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

Ответы [ 2 ]

2 голосов
/ 20 августа 2009

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

{% regroup notices by year as year_list %}


{% for year in year_list %}
  <h2>{{ year.grouper }}<h2>

  <ul>
  {% for notice in year.list %}
     <li>{{ notice.text }}</li>
  {% endfor %}
  </ul>
{% endfor %}

Существует также {% ifchanged %}, который может помочь с циклическим перебором списков, когда одно значение остается неизменным.

1 голос
/ 20 августа 2009

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

Проще всего, в шаблоне поставить:

{% for period in periods %}
    period.name
    {% for notice in period.notice_set.all %}
        notice.text
    {% endfor %}
{% endfor %}

Теперь это полностью исключает порядок, поэтому, если хотите, вы можете определить в своей Period модели:

def order_notices(self):
    return self.notice_set.order_by('order')

Тогда используйте

{% for period in periods %}
    period.name
    {% for notice in period.order_notices %}
        notice.text
    {% endfor %}
{% endfor %}

Если вы должны использовать годы, я настоятельно рекомендую определить метод в Year модели вида

def ordered_periods(self):
    ... #your logic goes here
    ... #should return an iterable (list or queryset) or periods

Тогда в вашем шаблоне:

{% for year in years %}
    year.name
    {% for period in year.ordered_periods %}
        period.name
        {% for notice in period.order_notices %}
            notice.text
        {% endfor %}
    {% endfor %}

EDIT: Помните, что секрет всего этого успеха заключается в том, что шаблон может вызывать только те методы, которые не принимают никаких аргументов (кроме self).

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