【问题标题】:In Django how to show a list of objects by year在Django中如何按年份显示对象列表
【发布时间】:2009-08-20 18:59:43
【问题描述】:

我有这些模型:

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
仲夏

  • 通知 1 中的文本 Lorem ipsum ...

  • 通知 2 中的文本 Lorem ipsum ...

九月

  • 通知 3 中的文本 Lorem ipsum ...

1950
一月

  • 通知 4 中的文本 Lorem ipsum ...

等等

我通过遍历所有行来构建嵌套列表找到了一个解决方案,如下所示:

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)

但这是缓慢且不雅的。这样做的好方法是什么?

如果我可以在模板中设置一些变量,我只能遍历所有通知,并且仅通过检查它们是否与前一个相同来打印年份和期间。但是不能在模板中设置一些临时变量。

【问题讨论】:

    标签: python django


    【解决方案1】:

    幸运的是,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 %},它可以帮助在一个值保持不变时循环遍历列表。

    【讨论】:

    • 谢谢,这正是我想要的!现在我只需要确保我的结果在传递给模板之前是正确的。
    【解决方案2】:

    如果不是因为您正在进行的不幸的非规范化,您的问题实际上不会那么难。我将忽略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 %}
    

    编辑: 请记住,所有这些成功的秘诀在于模板只能调用不带任何参数的方法(self 除外)。

    【讨论】:

    • 感谢您的回答。在模型方面移动更多东西是非常有趣的方法,这是一件好事。关于年份和时期。它们基本上是年和月,但月可能有奇怪的值(例如仲夏),年可能是一个范围(例如 1932-1940)。 Year 也可能有与之关联的图像。所以我不知道我该怎么做?
    • 我最大的建议是让期间指向年份,而通知仅指向期间。周期 p 的日期为 1963 年 6 月 1 日,y 年的日期为 1992 年 3 月 3 日,并且通知 n 与 y 和 p 相关联在逻辑上是否可能?如果没有,你有一个数据库设计问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-17
    • 1970-01-01
    • 2011-09-09
    • 2017-06-12
    • 2011-06-11
    相关资源
    最近更新 更多