← Back to team overview

schooltool-developers team mailing list archive

Re: More on schooltool.report

 

Hi,

On 01/27/2011 07:37 AM, Alan Elkner wrote:
Hey Guys,

After speaking with Tom about the report utility system I'm working
on, an additional benefit of the utility became clear.  At present,
schooltool.gradebook is the only package that has extensive reporting,
and as a result, it needed to create report request pages for the
various context types, schoolyear, term, section, person.  This
included a Reports action button for each context.
Right; so we should use an adapter instead of utility, so that we can adapt each context.
What we really need is for schooltool.report to provide these pages as
well as the Reports action link for each context, and it can use the
new registered utilities to generate the request view for each
context.  This means that one single utility registration will result
in two things: a report request link in the request view and the
appearance of the report in the reports reference view.

I think this will clear up the confusion Justas and I had regarding
the need for context type versus link.  We need them both.
Definitely, we need the utility to generate the link that
automatically appears in the report request view.  However, we also
need the interface itself to be one of the attributes so that we can
sub-divide the utilities by interface type.  We only want to put
schoolyear report request links in the schoolyear report request view.

This means that the current attributes for the utility are:

title
description
interface
getRequestLink()
getReferenceLink()
I assume getRequestLink is for Manage->Reports, getReferenceLink is for the reference view?
The lookup code for generating the request links for a specific
context would look like:

for name, util in getUtilitiesFor(IReportUtility):
     if util.interface.providedBy(self.context):
         links.append(util.getRequestLink())
Again with the if ISomeInterface.providedBy(context)... We have adapters for this task ;)

  Say, we define adapter instead of utility:

  class SomeReportLink(object):
    adapts(Interface, # instead of utility.interface
                schooltool.skin.skin.ISchoolToolLayer
    provides(IReportLink)

<adapter factory="SomeReportLink" name="some_report" />

  The *named* adapters gives us:

  links = []
  for adapter in getAdapters((self.context, self.request), IReportLink):
      links.append(adapter)

Note, that this is a multi-adapter on (context, request) - link generation often needs the request (say, for absoluteURL). And there's also skinning that changes things. Take Cambodia deployment for example. Skinned pages can get moved or removed, links change...

This design also splits getRequestLink and getReferenceLink to adapter.url() of two separate adapters. These links are for two separate views on two separate contexts - so they should be defined separately. One adapter to define the link in Manage->Reports. Another to define the link in a reference view.

As for the reports reference view, I will need to create a vocabulary
that maps the various interfaces to text that the user could
understand (School Year, Term, Group, etc.) and provide a drop-down
that allows for filtering by context type.  I'm assuming that such a
vocabulary that maps interface classes to text would be possible and
that it could be used easily in a table view.  Please correct me if
I'm wrong.

Any thoughts?
  I think classes implementing IReportLink should have:

  title = _("Link text")
  description = _("Link description")
  group = _("Group for filtering")
  @property
  def url(self):
     return absoluteURL(self.context, self.request) + '/rest/of/the/link'

You can now make the filtering vocabulary from unique group titles of collected adapters. Having group as a string instead of interface has its benefits - You can have "Teacher", "Student", "State-mandated-ethnicity-reports" report groups for the IBasicPerson interface...


Cheers,
Justas



P.S.: some thoughts on dynamic link generation... I couldn't resist.

Default adapter to keep the ability to directly register report links.

class DirectlyRegisteredReportLinkCollection(object):
   adapts(Interface,
               schooltool.skin.skin.ISchoolToolLayer
   provides(IReportLinkCollection)

   @property
   def links(self):
      # collect directly registered links
      return list(getAdapters((self.context, self.request), IReportLink))

Finally, change the report link views to use collections:

  links = []
for collection in getAdapters((self.context, self.request), IReportLinkCollection):
      links.extend(collection.links)

And now we can:

class ReportTermFailuresCollection(object):
   adapts(schooltool.schoolyear.interfaces.ISchoolYear
               schooltool.skin.skin.ISchoolToolLayer
   provides(IReportLinkCollection)

   @property
   def links(self):
       result = []
       schoolyear = self.context
       for term in schoolyear.values():
           base_url = absoluteURL(term)
           link = ReportLink()
           link.group=_("Term reports")
           link.title = term.title
           link.description=_("Failures by term")
           link.url = base_url + '/request_failing_report.html'
       return result

And here you go - school year "request links" page that also aggregates term failure reports :)





References