2009-08-20 51 views
1

顯示對象的名單上有論文型號:在Django中如何通過一年

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至40年
盛夏

  • 文字Lorem存有從通知1 ...

  • 文字Lorem存有從通知2 ...

從通知4 ...從通知

  • 文字Lorem存有...

1950年

  • 文字Lorem存有

我找到了一個解決方案通過遍歷所有的行內置嵌套列表如下:

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

幸運的是,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 %},它可以超過列表循環,當一個值保持不變幫助。

+0

謝謝,那就是我一直在尋找的!現在我只需要確保我的結果在傳遞給模板之前是正確的順序。 – Etienne 2009-08-20 19:30:48

1

如果不是那種不幸的反規範化,你的問題實際上並不那麼難。我要回答你的問題,忽略了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 %} 

如果您必須使用年限,我強烈建議在中定義方法形式

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 %} 

編輯: 請記住,祕密到這一切的成功是模板只能調用沒有方法採取任何論據(除了自我)。

+0

感謝您的回答。這是一個非常有趣的方法,在模型方面移動更多東西,這是一件好事。 大約年和週期。它們基本上是年份和月份,但月份可能有奇怪的值(例如中夏),年份可能是一個範圍(例如1932-1940)。 Year也可以有一個與之相關的圖像。所以我不知道我可以如何做到這一點? – Etienne 2009-08-20 19:43:47

+0

我最大的建議是將期限指向年份,通知指向期間。對於期間p來說,在1963年6月1日和y年的日期是1992年3月3日,並且通知n與y和p有關係嗎?如果沒有,你有一個數據庫設計問題。 – 2009-08-20 20:45:51