Skip to content

Commit 49d0544

Browse files
committed
Added experimental Calendar component
1 parent 08394b6 commit 49d0544

File tree

13 files changed

+1812
-0
lines changed

13 files changed

+1812
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ docs/Cells.rst
159159
docs/FormAutoConfig.rst
160160
docs/QueryAutoConfig.rst
161161
docs/TableAutoConfig.rst
162+
docs/Calendar.rst
162163
docs/views.rst
163164
docs/semantic_models.rst
164165
docs/M.rst

examples/examples/main_menu.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
),
4545
),
4646
tracks=M(view=views.TrackTable(auto__model=Track)),
47+
calendar=M(view=views.AlbumCalendar()),
4748
storybook=M(view=storybook.storybook),
4849
playground=M(view=playground.PlaygroundPage),
4950
iommi_admin=Admin.m(),
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 6.0.2 on 2026-02-27 08:00
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('examples', '0004_remove_dummy_models'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='album',
15+
name='published_date',
16+
field=models.DateField(blank=True, null=True, verbose_name='published date'),
17+
),
18+
]
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
from datetime import date
2+
3+
from django.db import migrations
4+
5+
# Real (or best-guess) release dates sourced from public knowledge.
6+
# Key: (artist_name, album_name) -> date
7+
RELEASE_DATES = {
8+
# Black Sabbath
9+
("Black Sabbath", "Black Sabbath"): date(1970, 2, 13),
10+
("Black Sabbath", "Paranoid"): date(1970, 9, 18),
11+
("Black Sabbath", "Master of Reality"): date(1971, 7, 21),
12+
("Black Sabbath", "Black Sabbath Vol. 4"): date(1972, 9, 25),
13+
("Black Sabbath", "Sabbath Bloody Sabbath"): date(1973, 12, 1),
14+
("Black Sabbath", "Sabotage"): date(1975, 7, 28),
15+
("Black Sabbath", "Technical Ecstasy"): date(1976, 9, 25),
16+
("Black Sabbath", "Never Say Die!"): date(1978, 9, 28),
17+
("Black Sabbath", "Live at Last"): date(1980, 6, 27),
18+
("Black Sabbath", "Heaven and Hell"): date(1980, 4, 25),
19+
("Black Sabbath", "Mob Rules"): date(1981, 11, 4),
20+
("Black Sabbath", "Live Evil"): date(1982, 12, 15),
21+
("Black Sabbath", "Born Again"): date(1983, 8, 7),
22+
("Black Sabbath", "Captured Live!"): date(1983, 8, 7),
23+
("Black Sabbath", "The Eternal Idol"): date(1987, 11, 24),
24+
("Black Sabbath", "Headless Cross"): date(1989, 4, 18),
25+
("Black Sabbath", "Tyr"): date(1990, 8, 20),
26+
("Black Sabbath", "Dehumanizer"): date(1992, 6, 22),
27+
("Black Sabbath", "Cross Purposes"): date(1994, 1, 31),
28+
("Black Sabbath", "Cross Purposes - Live"): date(1995, 4, 14),
29+
("Black Sabbath", "Forbidden"): date(1995, 6, 8),
30+
("Black Sabbath", "Reunion"): date(1998, 10, 20),
31+
("Black Sabbath", "Past Lives"): date(2002, 8, 27),
32+
("Black Sabbath", "Live at Hammersmith Odeon"): date(2007, 11, 27),
33+
("Black Sabbath", "13"): date(2013, 6, 10),
34+
("Black Sabbath", "Live... Gathered in Their Masses"): date(2013, 11, 22),
35+
("Black Sabbath", "The End"): date(2017, 11, 17),
36+
# Dio
37+
("Dio", "Holy Diver"): date(1983, 5, 25),
38+
("Dio", "The Last In Line"): date(1984, 7, 2),
39+
("Dio", "Sacred Heart"): date(1985, 8, 15),
40+
("Dio", "Intermission"): date(1986, 7, 28),
41+
("Dio", "Dream Evil"): date(1987, 7, 6),
42+
("Dio", "Lock Up The Wolves"): date(1990, 5, 14),
43+
("Dio", "Strange Highways"): date(1993, 11, 1),
44+
("Dio", "Angry Machines"): date(1996, 10, 15),
45+
("Dio", "Dio's Inferno - The Last In Live"): date(1997, 11, 18),
46+
("Dio", "Magica"): date(2000, 3, 21),
47+
("Dio", "Killing The Dragon"): date(2002, 5, 28),
48+
("Dio", "Master Of The Moon"): date(2004, 8, 30),
49+
("Dio", "Holy Diver Live"): date(2006, 4, 18),
50+
("Dio", "Live - We Rock"): date(2010, 4, 14),
51+
("Dio", "At Donington UK: Live 1983 & 1987"): date(2010, 9, 21),
52+
("Dio", "Finding The Sacred Heart \u2013 Live In Philly 1986 \u2013"): date(2013, 6, 18),
53+
("Dio", "Live In London Hammersmith Apollo 1993"): date(2014, 2, 11),
54+
("Dio", "Donington '87"): date(2022, 5, 20),
55+
("Dio", "Donington '83"): date(2022, 5, 20),
56+
# Ozzy Osbourne
57+
("Ozzy Osbourne", "Blizzard Of Ozz"): date(1980, 9, 20),
58+
("Ozzy Osbourne", "Diary Of A Madman"): date(1981, 11, 7),
59+
("Ozzy Osbourne", "Speak Of The Devil"): date(1982, 11, 27),
60+
("Ozzy Osbourne", "Bark At The Moon"): date(1983, 11, 15),
61+
("Ozzy Osbourne", "The Ultimate Sin"): date(1986, 2, 22),
62+
("Ozzy Osbourne", "King Biscuit Flower Hour [Airdate: August 24, 1986]"): date(1986, 8, 24),
63+
("Ozzy Osbourne", "Tribute"): date(1987, 3, 19),
64+
("Ozzy Osbourne", "No Rest For The Wicked"): date(1988, 9, 28),
65+
("Ozzy Osbourne", "No More Tears"): date(1991, 9, 17),
66+
("Ozzy Osbourne", "Live & Loud"): date(1993, 6, 22),
67+
("Ozzy Osbourne", "Ozzmosis"): date(1995, 10, 23),
68+
("Ozzy Osbourne", "Down To Earth"): date(2001, 10, 16),
69+
("Ozzy Osbourne", "Live at Budokan"): date(2002, 6, 25),
70+
("Ozzy Osbourne", "Under Cover"): date(2005, 11, 1),
71+
("Ozzy Osbourne", "Black Rain"): date(2007, 5, 22),
72+
("Ozzy Osbourne", "Scream"): date(2010, 6, 15),
73+
("Ozzy Osbourne", "Ozzy Live"): date(2012, 9, 3),
74+
("Ozzy Osbourne", "Ordinary Man"): date(2020, 2, 21),
75+
("Ozzy Osbourne", "Patient Number 9"): date(2022, 9, 9),
76+
# Radiohead
77+
("Radiohead", "Pablo Honey"): date(1993, 2, 22),
78+
("Radiohead", "The Bends"): date(1995, 3, 13),
79+
("Radiohead", "OK Computer"): date(1997, 6, 16),
80+
("Radiohead", "In Concert - 725"): date(1997, 7, 25),
81+
("Radiohead", "Kid A"): date(2000, 10, 2),
82+
("Radiohead", "Amnesiac"): date(2001, 6, 5),
83+
("Radiohead", "Hail To The Thief"): date(2003, 6, 9),
84+
("Radiohead", "In Rainbows"): date(2007, 10, 10),
85+
("Radiohead", "In Rainbows Disk 2"): date(2009, 8, 11),
86+
("Radiohead", "The King Of Limbs"): date(2011, 2, 18),
87+
("Radiohead", "A Moon Shaped Pool"): date(2016, 5, 8),
88+
("Radiohead", "Minidiscs (Hacked)"): date(2019, 6, 18),
89+
# Tony Iommi
90+
("Tony Iommi", "Iommi"): date(2000, 10, 16),
91+
("Tony Iommi", "Fused"): date(2005, 7, 12),
92+
# Django Reinhardt – exact dates are mostly unknown for these
93+
# compilations/reissues, using Jan 1 of the release year.
94+
("Django Reinhardt", "Django Reinhardt Und Der Hot Club De France"): date(1929, 1, 1),
95+
("Django Reinhardt", "Django And His American Friends Vol. 1"): date(1930, 1, 1),
96+
("Django Reinhardt", "Django Reinhardt y el Quinteto del Hot Club de Francia"): date(1932, 1, 1),
97+
("Django Reinhardt", "Django And His American Friends, Vol. 2"): date(1935, 1, 1),
98+
("Django Reinhardt", "Djangology"): date(1936, 1, 1),
99+
("Django Reinhardt", "The Great Artistry Of Django Reinhardt"): date(1953, 1, 1),
100+
("Django Reinhardt", "Souvenirs De Django Reinhardt Volume 2"): date(1954, 1, 1),
101+
("Django Reinhardt", "Django (Volume 1)"): date(1957, 1, 1),
102+
("Django Reinhardt", "Volume 2"): date(1957, 1, 1),
103+
("Django Reinhardt", "Django Volume V"): date(1959, 1, 1),
104+
("Django Reinhardt", "Django - Volume 8"): date(1959, 1, 1),
105+
("Django Reinhardt", "Django Reinhardt Europe's Greatest Contribution To Jazz"): date(1964, 1, 1),
106+
("Django Reinhardt", "And His Jazz Guitar"): date(1966, 1, 1),
107+
("Django Reinhardt", "Django"): date(1969, 1, 1),
108+
("Django Reinhardt", "Django Reinhardt (Volume II)"): date(1969, 1, 1),
109+
("Django Reinhardt", "Django, Mon Fr\u00e8re"): date(1969, 1, 1),
110+
("Django Reinhardt", "Djangologie 15 (1946-1947)"): date(1970, 1, 1),
111+
("Django Reinhardt", "Djangologie 19"): date(1971, 1, 1),
112+
("Django Reinhardt", "Django 1934 - Les Premiers Enregistrements Du Quintette Du H.C.F."): date(1972, 1, 1),
113+
("Django Reinhardt", "Django \u00b435-\u00b439 - The Quintet Of The Hot Club Of France"): date(1973, 1, 1),
114+
("Django Reinhardt", "Django Reinhardt"): date(1976, 1, 1),
115+
("Django Reinhardt", "Nuages (Radio Sessions 1947, Vol. 1)"): date(1980, 1, 1),
116+
("Django Reinhardt", "Django Reinhardt Au Club St-Germain-Des-Pr\u00e9s"): date(1983, 1, 1),
117+
("Django Reinhardt", "Le Quintette Du Hot Club De France Feat. Stephane Grappelly"): date(1984, 1, 1),
118+
("Django Reinhardt", "Djangology 49"): date(1990, 1, 1),
119+
("Django Reinhardt", "Swing 39"): date(2000, 1, 1),
120+
("Django Reinhardt", "Django Et Compagnie (Jazz In Paris)"): date(2000, 1, 1),
121+
("Django Reinhardt", "Django's Blues"): date(2001, 1, 1),
122+
("Django Reinhardt", "Et Le Hot Club De France"): date(2004, 1, 1),
123+
# Quintette Du Hot Club De France
124+
("Quintette Du Hot Club De France", "The Quintet Of The Hot Club Of France - Volume 2"): date(1943, 1, 1),
125+
("Quintette Du Hot Club De France", "Swing '35-'39"): date(1970, 1, 1),
126+
}
127+
128+
129+
def populate_published_date(apps, schema_editor):
130+
Album = apps.get_model('examples', 'Album')
131+
for album in Album.objects.select_related('artist').all():
132+
key = (album.artist.name, album.name)
133+
d = RELEASE_DATES.get(key)
134+
if d is None:
135+
# Fallback: use Jan 1 of the album year
136+
d = date(album.year, 1, 1)
137+
album.published_date = d
138+
album.save(update_fields=['published_date'])
139+
140+
141+
def reverse_populate(apps, schema_editor):
142+
Album = apps.get_model('examples', 'Album')
143+
Album.objects.all().update(published_date=None)
144+
145+
146+
class Migration(migrations.Migration):
147+
dependencies = [
148+
('examples', '0005_add_album_published_date'),
149+
]
150+
151+
operations = [
152+
migrations.RunPython(populate_published_date, reverse_populate),
153+
]

examples/examples/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class Album(models.Model):
2121
name = models.CharField(max_length=255, db_index=True, verbose_name=_('name'))
2222
artist = models.ForeignKey(Artist, on_delete=models.CASCADE, related_name='albums', verbose_name=_('artist'))
2323
year = models.IntegerField(verbose_name=_('year'))
24+
published_date = models.DateField(null=True, blank=True, verbose_name=_('published date'))
2425

2526
def __str__(self):
2627
return self.name

examples/examples/views.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import iommi.style
77
from iommi import (
8+
Calendar,
89
Header,
910
Page,
1011
html,
@@ -116,6 +117,27 @@ class AlbumPage(Page):
116117
)
117118

118119

120+
def _latest_album_year(**_):
121+
latest = Album.objects.latest('published_date')
122+
return latest.published_date.year
123+
124+
125+
def _latest_album_month(**_):
126+
latest = Album.objects.latest('published_date')
127+
return latest.published_date.month
128+
129+
130+
class AlbumCalendar(Page):
131+
title = Header('Album releases')
132+
calendar = Calendar(
133+
rows=Album.objects.all(),
134+
event__attr='published_date',
135+
event__display_name=lambda event, **_: event.name,
136+
year=_latest_album_year,
137+
month=_latest_album_month,
138+
)
139+
140+
119141
class IndexPage(ExamplesPage):
120142
logo = html.img(
121143
attrs__src='https://docs.iommi.rocks/_static/logo_with_outline.svg',

0 commit comments

Comments
 (0)