import datetime from django.utils.text import slugify from django.utils.timezone import make_aware from .models import Thought class Page: def __init__(self, formatted_name): self.formatted_name = formatted_name self.slug = slugify(formatted_name) def get_all_entries(self): pass # Okay we're going to use some wack seasons here hold on # Let's go meteorological seasons # 1 - jan -> 1, 0 # 2 - feb -> 2, 0 # 3 - mar -> 3, 1, spring # 4 - apl -> 4, 1 # 5 - may -> 5, 1 # 6 - jun -> 6, 2, summer # 7 - jul -> 7, 2 # 8 - aug -> 8, 2 # 9 - sep -> 9, 3, fall # 10 - oct -> 10, 3 # 11 - nov -> 11, 3 # 12 - dec -> 0, 0, winter def season_for_date(date): return (date.month % 12) // 3 def season_year_for_date(date): return season_for_date(date), date.year - (1 if date.month in [1, 2] else 0) def formatted_name_for_season_year(current_season, current_year): return ["Winter", "Spring", "Summer", "Fall"][current_season] + " " + str(current_year) def get_page_slug(thought): return slugify(formatted_name_for_season_year(*season_year_for_date(thought.posted))) class SeasonPage(Page): def __init__(self, current_season, current_year): super().__init__(formatted_name_for_season_year(current_season, current_year)) self.first_day_of_season = make_aware(datetime.datetime( current_year, 12 if current_season == 0 else current_season * 3, 1 )) # If the current season is winter, then the next season starts on the next year # This is actually the first day of the next season but that's hard to type out and it's 2am self.last_day_of_season = make_aware(datetime.datetime( current_year + (1 if current_season == 0 else 0), 12 if current_season == 3 else (current_season + 1) * 3, 1 )) def get_all_entries(self): return Thought.objects.order_by("-posted").filter( posted__gte=self.first_day_of_season, # First month of this season posted__lt=self.last_day_of_season # First month of next season ) # Need to loop over all thoughts? and yield a new Page for each season # Assume that if you're using this generator, you have at least 1 thought each # season between the first and last # We don't take into account timezone here. Because local time isn't monotonic increasing, # it's ill-defined how to split up a list of items ordered by server time. This is annoying # But the alternative is to call get_season for every thought and sort them into buckets def season_pages(): ordered_thoughts = Thought.objects.order_by("posted") first_thought = ordered_thoughts.first() last_thought = ordered_thoughts.last() current_season, current_year = season_year_for_date(first_thought.posted) last_season, last_year = season_year_for_date(last_thought.posted) while current_year < last_year or current_season != last_season: yield SeasonPage(current_season, current_year) if current_season == 0: current_year += 1 current_season += 1 current_season = current_season % 4 yield SeasonPage(current_season, current_year) def get_all_pages(): pages = list(season_pages()) pages.reverse() return pages # Where a Page has: # .slug # .formatted_name # .get_all_entries # return [Pages]