Quantcast

Using Django with groupby

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Using Django with groupby

Will Holmes
Hi guys,

I am using django to develop a calendar web app where users can create events that are then displayed on a month by month view.

I have written a custom template tag that takes Python's HTMLCalendar formatmonth function and overlays events that are on that day. 

It is currently set up to take the start date of the event directly from each event and then use groupby to group each event by the day of the month in a dictionary. These can then be overlaid on the calendar. This, however, is not particularly useful if an event occurs over multiple days. 

I want to find a way of taking each of the days the event occurs over, start date to end date, before returning a similar dictionary. However, I cannot seem to get this to work whichever way I try it. Here is the group_by_day function that currently groups the events by start date:

#Here is where the code groups events for the relevant month day
def group_by_day(self, events):
    field
= lambda event: event.start_date.day
   
return dict(
       
[(day, list(items)) for day, items in groupby(events, field)]
   
)


Can anyone suggest a way round this problem?

If you need any more information please let me know. The project can be viewed in entirety at https://github.com/Willrholmes01/organiser.

Below is the entire template tag:

register = template.Library()

def do_month_calendarify(parser, token):
   
# Take the tag input from the template and format
   
# Template syntax is {% calendarify year month %}
   
try:
        tag_name
, year, month, event_list = token.split_contents()
   
except ValueError:
       
raise template.TemplateSyntaxError(
           
"%r tag requires three arguments" % token.contents.split()[0]
       
)
   
return CalendarifyNode(year, month, event_list)

class CalendarifyNode(template.Node):

   
def __init__(self, year, month, event_list):
       
try:
           
self.year = template.Variable(year)
           
self.month = template.Variable(month)
           
self.event_list = template.Variable(event_list)
       
except ValueError:
           
raise template.TemplateSyntaxError

   
def render(self, context):
       
try:
            my_year
= self.year.resolve(context)
            my_month
= self.month.resolve(context)
            my_event_list
= self.event_list.resolve(context)
            cal
= EventCalendar(my_event_list)
           
return cal.formatmonth(
               
int(my_year), int(my_month))
       
except ValueError:
           
return "%s, %s, %s" % (my_month, my_year, my_event_list)

class EventCalendar(HTMLCalendar):
   
# Use Python's HTMLCalendar and put user events over top
   
def __init__(self, events):
       
super(EventCalendar, self).__init__()
       
self.events = self.group_by_day(events)

   
def formatday(self, day, weekday):
       
if day != 0:
            cssid
= self.cssclasses[weekday]
            cssclass
= "daybox"
           
if date.today() == date(self.year, self.month, day):
                cssid
+= ' today'
           
if day in self.events:
                cssid
+= ' filled'
                body
= ['<ul>']
               
for event in self.events[day]:
                    body
.append('<li>')
                    body
.append('<a id="event_%d" href="%s">'
                                   
% (event.id, event.get_absolute_url()))
                    body
.append(esc(event.title))
                    body
.append('</a></li>')
                body
.append('</ul>')
               
return self.day_cell(
                    cssclass
, cssid, '<span class="dayNumber">%d</span> %s' % (
                        day
, ''.join(body)))
           
return self.day_cell(
                cssclass
, cssid, '<span class="dayNumberNoReadings">%d</span>' % (day))
       
return self.day_cell('nodaybox', 'noday', '&nbsp;')

   
def formatmonth(self, year, month):
       
self.year, self.month = year, month
       
return super(EventCalendar, self).formatmonth(year, month)

   
#Here is where the code groups events for the relevant month day
   
def group_by_day(self, events):
        field
= lambda event: event.start_date.day
       
return dict(
           
[(day, list(items)) for day, items in groupby(events, field)]
       
)

   
def day_cell(self, cssclass, cssid, body):
       
return '<td class="%s" id="%s">%s</td>' % (cssclass, cssid, body)

register.tag('calendarify', do_month_calendarify)






--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/775bc7f8-46e3-4fb2-9581-35d05ceb812e%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Using Django with groupby

Will Holmes
Fixed this by just not using groupby. So far I just have a slightly long-winded work around that formats the data in the same way as groupby but includes all days in in between, and including, the start date and end date.

def group_by_day(self, events, month):
        return_dict = {}
        for event in events:
            if event.end_date != None:
                number_days = event.end_date - event.start_date
                day_range = [event.start_date + timedelta(
                    days=i) for i in range(number_days.days + 1)]
                for date in day_range:
                    if date.month == month:
                        if date.day in return_dict:
                            return_dict[date.day].append(event)
                        else:
                            return_dict[date.day] = [event]
            else:
                if event.start_date.day in return_dict:
                    return_dict[event.start_date.day].append(event)
                else:
                    return_dict[event.start_date.day] = [event]
        return return_dict



On Thursday, April 20, 2017 at 4:35:36 PM UTC+1, Will Holmes wrote:
Hi guys,

I am using django to develop a calendar web app where users can create events that are then displayed on a month by month view.

I have written a custom template tag that takes Python's HTMLCalendar formatmonth function and overlays events that are on that day. 

It is currently set up to take the start date of the event directly from each event and then use groupby to group each event by the day of the month in a dictionary. These can then be overlaid on the calendar. This, however, is not particularly useful if an event occurs over multiple days. 

I want to find a way of taking each of the days the event occurs over, start date to end date, before returning a similar dictionary. However, I cannot seem to get this to work whichever way I try it. Here is the group_by_day function that currently groups the events by start date:

#Here is where the code groups events for the relevant month day
def group_by_day(self, events):
    field
= lambda event: event.start_date.day
   
return dict(
       
[(day, list(items)) for day, items in groupby(events, field)]
   
)


Can anyone suggest a way round this problem?

If you need any more information please let me know. The project can be viewed in entirety at <a href="https://github.com/Willrholmes01/organiser" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2FWillrholmes01%2Forganiser\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGysZCrWDuMDcWSZULj7kvbX3xNPA&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2FWillrholmes01%2Forganiser\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGysZCrWDuMDcWSZULj7kvbX3xNPA&#39;;return true;">https://github.com/Willrholmes01/organiser.

Below is the entire template tag:

register = template.Library()

def do_month_calendarify(parser, token):
   
# Take the tag input from the template and format
   
# Template syntax is {% calendarify year month %}
   
try:
        tag_name
, year, month, event_list = token.split_contents()
   
except ValueError:
       
raise template.TemplateSyntaxError(
           
"%r tag requires three arguments" % token.contents.split()[0]
       
)
   
return CalendarifyNode(year, month, event_list)

class CalendarifyNode(template.Node):

   
def __init__(self, year, month, event_list):
       
try:
           
self.year = template.Variable(year)
           
self.month = template.Variable(month)
           
self.event_list = template.Variable(event_list)
       
except ValueError:
           
raise template.TemplateSyntaxError

   
def render(self, context):
       
try:
            my_year
= self.year.resolve(context)
            my_month
= self.month.resolve(context)
            my_event_list
= self.event_list.resolve(context)
            cal
= EventCalendar(my_event_list)
           
return cal.formatmonth(
               
int(my_year), int(my_month))
       
except ValueError:
           
return "%s, %s, %s" % (my_month, my_year, my_event_list)

class EventCalendar(HTMLCalendar):
   
# Use Python's HTMLCalendar and put user events over top
   
def __init__(self, events):
       
super(EventCalendar, self).__init__()
       
self.events = self.group_by_day(events)

   
def formatday(self, day, weekday):
       
if day != 0:
            cssid
= self.cssclasses[weekday]
            cssclass
= "daybox"
           
if date.today() == date(self.year, self.month, day):
                cssid
+= ' today'
           
if day in self.events:
                cssid
+= ' filled'
                body
= ['<ul>']
               
for event in self.events[day]:
                    body
.append('<li>')
                    body
.append('<a id="event_%d" href="%s">'
                                   
% (event.id, event.get_absolute_url()))
                    body
.append(esc(event.title))
                    body
.append('</a></li>')
                body
.append('</ul>')
               
return self.day_cell(
                    cssclass
, cssid, '<span class="dayNumber">%d</span> %s' % (
                        day
, ''.join(body)))
           
return self.day_cell(
                cssclass
, cssid, '<span class="dayNumberNoReadings">%d</span>' % (day))
       
return self.day_cell('nodaybox', 'noday', '&nbsp;')

   
def formatmonth(self, year, month):
       
self.year, self.month = year, month
       
return super(EventCalendar, self).formatmonth(year, month)

   
#Here is where the code groups events for the relevant month day
   
def group_by_day(self, events):
        field
= lambda event: event.start_date.day
       
return dict(
           
[(day, list(items)) for day, items in groupby(events, field)]
       
)

   
def day_cell(self, cssclass, cssid, body):
       
return '<td class="%s" id="%s">%s</td>' % (cssclass, cssid, body)

register.tag('calendarify', do_month_calendarify)






--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/a9c0e243-5b21-486e-9fa3-5f0d2ba3fbad%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...