After seeing all the other posts, I completely rewrote the whole thing. I grouped the data in the controller so that entries on the same day will be in the same list, making easier to put each day of entries into its own table. I have really advanced the whole thing since my original post. Here is my controller:
def format_minutes(minutes): hours = round(minutes / 60) if hours == 0: return "00:%02d" % (minutes) else: minutes -= minutes * hours return "%02d:%02d" % (hours, minutes) def format_full_date(the_date): return the_date.strftime('%A, %B %d, %Y') # get information from database week_start, week_end = timeclock.get_week_range_for_date() rows = timeclock.list_for_user(auth.user, week_start, week_end) minutes_worked = timeclock.get_minutes_for_this_week(auth.user) minutes_vacation = timeclock.get_minutes_for_this_week(auth.user, 2) minutes_personal = timeclock.get_minutes_for_this_week(auth.user, 3) minutes_sick = timeclock.get_minutes_for_this_week(auth.user, 4) minutes_total = minutes_worked + minutes_vacation + minutes_personal + minutes_sick # begin formatting minutes for the week hours_worked = format_minutes(minutes_worked) hours_vacation = format_minutes(minutes_vacation) hours_personal = format_minutes(minutes_personal) hours_sick = format_minutes(minutes_sick) hours_total = format_minutes(minutes_total) # group entries together to make it easier for the view grouped_entries = dict() for row in rows: full_date = format_full_date(row.calculated_start) if full_date in grouped_entries: grouped_entries[full_date].append(row) else: grouped_entries[full_date] = [row] return dict(grouped_entries=grouped_entries, hours_worked=hours_worked, hours_vacation=hours_vacation, hours_personal=hours_personal, hours_sick=hours_sick, hours_total=hours_total ) And this is my view: {{extend 'layout.html'}} {{import datetime}} <h1>Time Clock for {{=auth.user.first_name}} {{=auth.user.last_name}}</h1> {{still_clocked_in = False}} <div id="timeclock_list"> {{if len(grouped_entries) > 0:}} {{ def format_time_string(the_date): if the_date is None: return 'Still clocked in' return the_date.strftime('%I:%M %p') def format_minutes(minutes): hours = round(minutes / 60) if hours == 0: return "00:%02d" % (minutes) else: minutes -= minutes * hours return "%02d:%02d" % (hours, minutes) pass }} {{for k, v in grouped_entries.iteritems():}} <h4>{{=k}}</h4> <table><thead><tr><th>Time in:</th><th>Time out:</th><th>Type:</th><th>Hours:</th></tr></thead><tbody> {{total_for_day = 0}} {{for entry in v:}} {{ if entry.calculated_minutes is None: still_clocked_in = True entry_hours = '' else: total_for_day += entry.calculated_minutes entry_hours = format_minutes(entry.calculated_minutes) pass date_start = format_time_string(entry.calculated_start) date_end = format_time_string(entry.calculated_end) entry_type = db.timeclock_events[entry.event_type] }} <tr><td>{{=date_start}}</td><td>{{=date_end}}</td><td>{{=entry_type}}</td><td class="center">{{=entry_hours}}</td></tr> {{pass}} {{total_for_day_formatted = format_minutes(total_for_day)}} </tbody><tfoot><tr><th class="right" colspan="3">Total for day:</th><th>{{=total_for_day_formatted}}</th></tr></tfoot></table> {{pass}} </div> <div id="timeclock_totals"> <h4>Totals for week</h4> <table><tbody> {{if hours_worked != '00:00':}} <tr><td>Total hours worked this week:</td><td class="center">{{=hours_worked}}</td></tr> {{pass}} {{if hours_vacation != '00:00':}} <tr><td>Total hours of vacation this week:</td><td class="center">{{=hours_vacation}}</td></tr> {{pass}} {{if hours_personal != '00:00':}} <tr><td>Total hours of personal time this week:</td><td class="center">{{=hours_personal}}</td></tr> {{pass}} {{if hours_sick != '00:00':}} <tr><td>Total hours sick this week:</td><td class="center">{{=hours_sick}}</td></tr> {{pass}} </tbody><tfoot> <tr><th class="right">Grand total for this week:</th><th>{{=hours_total}}</th></tr> </tfoot></table> {{else:}} <h5>No time clock entries for this week.</h5> {{pass}} </div> {{ if still_clocked_in: punch_text = 'Clock out' else: punch_text = 'Clock in' pass response.write(A(punch_text, _href=URL('punch'), _id='timeclock_punch', _class='no_print')) }} There is a lot more code because I have since added a lot functionality, but I think the code itself is fairly clean. I put most of the computational stuff in the controller, and only a couple of things needed to be formatted for the view. On Mar 3, 2011, at 4:07 PM, Anthony wrote: > On Thursday, March 3, 2011 10:31:18 AM UTC-5, Ross Peoples wrote: > I know that web2py has HTML helpers like TABLE(), TR(), etc, but how would I > build a table in this way, while in a for loop? This is what I tried so far, > but it fails so horribly I don't even know where the error is: > > {{extend 'layout.html'}} > <h1>Time Clock for {{=user.first_name}} {{=user.last_name}}</h1> > {{if len(rows) > 0:}} > {{ > def get_day_of_year(the_date): > return the_date.timetuple().tm_yday > > def full_date_name(the_date): > return the_date.strftime('%A, %B %d, %Y') > > def time_string(the_date): > return the_date.strftime('%I:%M %p') > > prev_day_of_year = None > tables = [] > trs = None > for row in rows: > if get_day_of_year(row.calculated_start) != prev_day_of_year: > if trs is not None: > tables[] = (H4(full_date_name(row.calculated_start)), trs) > trs = [] > > trs[] = TR((TD(time_string(row.calculated_start)), > TD(time_string(row.calculated_end)))) > prev_day_of_year = get_day_of_year(row.calculated_start) > else: > trs[] = TR((TD(time_string(row.calculated_start)), > TD(time_string(row.calculated_end)))) > > Am I missing something here? Where are you building a table -- I don't see > any calls to TABLE(), just TR(). Also, I'm not sure about your syntax. It > looks like you are passing a tuple of TD's to TR instead of passing the TD's > as separate arguments (i.e., there's an extra set of parentheses inside TR). > Finally, what is 'trs[] =' doing -- I think that will raise a syntax error. > You should be able to create a table object (e.g., table = TABLE()), and then > append TR's to it via append -- e.g., table.append(TR('cell 1', 'cell 2')). > > Anthony >