ls.joyous
ls.joyous copied to clipboard
Merging events from two calendars...
I've been loving Joyous Calendar and Wagtail so much. It's just great software.
I have a main CalendarPage at the root of my site where I'd like to keep events that should display on all other calendars on the site. How would I reach back up to that calendar to display those events on a calendar that exists down the page tree? I'm using a custom class based on CalendarPage as my sub-calendars, so I tried to get the top-level CalendarPage and the merge the events, but I get a "Models aren't loaded yet." error.
Any ideas on this problem?
So, if I understand correctly your site is structured something like this?
Home-Calendar
+--- Sub-Calendar1
| +--- Event1
| +--- Event2
+--- Sub-Calendar2
+--- Event3
+--- Event4
Where: Event1 and Event2 should appear in Sub-Calendar1; Event3 and Event4 should appear in Sub-Calendar2; And all the events 1,2,3,4 should appear in Home-Calendar?
Joyous was designed to support just this. You don't need to "reach up" to merge in events, instead the Calendars "reach down" to pull in events. (Hope that makes sense.)
- The CalendarPage class will search for all the events in the site, no matter what their parent. So it (or something derieved from it) can be used for Home-Calendar.
- The SpecificCalendarPage class searches only for those events which are children of itself. So it (or something derieved from it) can be used for the Sub-Calendars.
Normally SpecificCalendarPage is disabled. To enable it you'll need to add
SpecificCalendarPage.is_creatable = True
in your models.py, or defineis_creatable
asTrue
in your derieved class.
Or derive your own version of CalendarPage with some other kind of event selection.
Hope that helps.
Sorry, I didn't explain myself very well. You have the structure correct, but I want to reach up so that Sub-Calendar1 and Sub-Calendar2 show their respective child events and the events from Home-Calendar. I'm actually using a derived CalendarPage for the "sub calendars" already, which I tried to use to pull in the Home-Calendar events, which is what brought up the "Models aren't loaded yet" error.
I'll make it more concrete. This is for a school district website. The top level calendar is for "All-district" events. Then under that there are individual school calendars:
District-Calendar
+---High School Calendar
| +---Event1
| +---Event2
+---Middle School Calendar
| +---Event3
| +---Event4
So each school calendar should show its events as well as any all-district events.
Thanks for the quick reply and for making some sweet software!
Thanks for the clarification. I guess I was just looking for the question I already had an answer for :-).
I think your approach in subclassing the school calendars is the correct one (more suggestions on that further down). I can't say why you are getting the "Models aren't loaded yet" error. You'll have seen it suggests that you are trying to use models before all the applications have loaded. If you can share the stack trace, I might be able to help further.
For ease of implementation, would the following structure still work for you?
HomePage (render the District-Calendar content)
+---District-Calendar (slug=district-calendar)
| +---Event0
+---High School Calendar
| +---Event1
| +---Event2
+---Middle School Calendar
| +---Event3
| +---Event4
This would make it easier to identify what is an all-district event (e.g. Event0) and what events are specific to a school. The site could look the same to viewers, but editors would need to know where too look for the all-district events.
None of the code below is tested (will be buggy), but this is my idea of how the sub-class could be implemented. If I get time I will try and get a real example working.
It is an interesting exercise thinking how to extend Joyous like this. Thanks! I can see some possibilities for future changes to make this kind of thing simpler.
class MergedCalendarPage(ProxyPageMixin, CalendarPage):
"""
MergedCalendarPage displays the events which are its children or the
children of the merged page
"""
class Meta(ProxyPageMixin.Meta):
verbose_name = "merged calendar page"
verbose_name_plural = "merged calendar pages"
MERGE_IN_SLUG = "district-calendar"
@classmethod
def _allowAnotherAt(cls, parent):
return True
def _getEventsByDay(self, request, firstDay, lastDay):
merged = Page.objects.get(slug=self.MERGE_IN_SLUG)
evods = []
myEvods = getAllEventsByDay(request, firstDay, lastDay,
home=self, holidays=self.holidays)
mergeEvods = getAllEventsByDay(request, firstDay, lastDay,
home=merged, holidays=self.holidays)
for myEvod, mergeEvod in zip(myEvods, mergeEvods):
day = myEvod.date
days_events = myEvod.days_events + mergeEvod.days_events
continuing_events = myEvod.continuing_events + mergeEvod.continuing_events
def sortByTime(thisEvent):
fromTime = thisEvent.page._getFromTime(atDate=day)
if fromTime is None:
fromTime = dt.time.max
return fromTime
days_events.sort(key=sortByTime)
evods.append(EventsOnDay(day, myEvods.holiday, days_events, continuing_events))
return evods
def _getEventsByWeek(self, request, year, month):
return _getEventsByWeek(year, month,
partial(self._getEventsByDay, request))
def _getUpcomingEvents(self, request):
merged = Page.objects.get(slug=self.MERGE_IN_SLUG)
myEvents = getAllUpcomingEvents(request, home=self, holidays=self.holidays)
mergeEvents = getAllUpcomingEvents(request, home=merged, holidays=self.holidays)
events = sorted(myEvents + mergeEvents, key=_getUpcomingSort())
return events
def _getPastEvents(self, request):
merged = Page.objects.get(slug=self.MERGE_IN_SLUG)
myEvents = getAllPastEvents(request, home=self, holidays=self.holidays)
mergeEvents = getAllPastEvents(request, home=merged, holidays=self.holidays)
events = sorted(myEvents + mergeEvents,
key=attrgetter('page._past_datetime_from'), reverse=True)
return events
def _getEventFromUid(self, request, uid):
merged = Page.objects.get(slug=self.MERGE_IN_SLUG)
event = getEventFromUid(request, uid) # might raise exception
if event.get_ancestors().filter(id__in=[self.id, merged.id]).exists():
# only return event if it is a descendant
return event
def _getAllEvents(self, request):
merged = Page.objects.get(slug=self.MERGE_IN_SLUG)
myEvents = getAllEvents(request, home=self, holidays=self.holidays)
mergeEvents = getAllEvents(request, home=merged, holidays=self.holidays)
events = myEvents + mergeEvents
return events
class HomePage(Page):
"""HomePage displays the District-Calendar."""
subpage_types = ['ls.joyous.SpecificCalendarPage']
MERGE_IN_SLUG = "district-calendar"
def route(self, request, path_components):
subpage = Page.objects.get(slug=self.MERGE_IN_SLUG)
try:
return subpage.specific.route(request, path_components)
except Http404:
pass
return super().route(request, path_components)
Awesome, I will dig into this and let you know what happens. Hopefully it can be useful to you to expand the project.