Follow

Migrating Custom Report Plugins (from pre-3.4 to 3.4 and above)

Introduction

Custom report plugins have changed slightly in 3.4 and certain modifications are required for them to work with SD Elements 3.4 and above.

Prior to 3.4, custom report plugins worked by returning a HTTPResponse object via the get_response method. This required plugin authors to have a basic understanding of Django and implement their own rendering methods.

In 3.4, custom report plugins are simplified so that plugin authors need only to write code for the business logic of their plugins.

In particular, the get_response method has been replaced by get_context. The plugin needs only to return a Python dict containing the data required for the report. There are three available built-in rendering methods included in SD Elements 3.4 and above-- HTML, PDF, and CSV.

Example

As report plugins are, by nature, custom, it would be impossible to cover all possible cases. Hence, the main points are illustrated by way of a simple plugin. In the code sample below, the get_response method supports HTML and PDF formats and displays custom logos for the PDF report.

# other imports...
from report_plugins.models import BaseReportPlugin class PlannedSecurityReportPlugin(BaseReportPlugin):
# other methods
def get_response(self, request, context): pdf_format = context.get('format') == 'pdf' project = self.meta.get('project') context = { 'title': self.title, 'description': self.description, 'project': project, 'STATIC_URL': settings.STATIC_URL, 'today': datetime.date.today(), 'planned_tasks': self.get_planned_tasks(project), # business logic 'THEME_LOGOS': get_logos_dict(self.meta.get('org')) } context.update({'UI_STRS': settings.UI_STRS}) if pdf_format: context.update({'type': 'pdf'}) context = Context(context) template = get_template(self.template) response = generate_pdf_from_template(template, context, self.meta.get('org')) return response_as_download("planned-security-report.pdf", response) return render_to_response(self.template, context)

The first thing that needs to be changed is the import. In 3.4 and above, the BaseReportPlugin lives in sdetools instead of SD Elements. Please ensure that your sdetools version is v5.0.0 or above.

# from report_plugins.models import BaseReportPlugin
from sdetools.sde_plugins.report_plugin import BaseReportPlugin

Next, replace the get_response method with a get_context method and specify the filename for file downloads without the suffix. The suffix will be automatically added depending on the format of report requested.

class PlannedSecurityReportPlugin(BaseReportPlugin):
filename = 'planned-security-report'
# as above...

def get_context(self, request, context):
context = super(PlannedSecurityReportPlugin, self).get_context(request, context) project = self.meta.get('project')
# data specific to this plugin
context.update({
'planned_tasks': self.get_planned_tasks(project)
})

return context

Finally, change REPORT_PLUGINS_FOLDER setting in local_settings.py to PROJECT_REPORT_PLUGINS_FOLDER instead.

Important:

Much of the data common to most reports are automatically included in the BaseReportPlugin. Thus, for the reports to render properly, it is imperative that the custom report get its superclass's context via super(MyPluginClass, self).get_context(request, context) call. For more information about what the default context contains, see here (external link).

CSV support

Built-in support for CSV has also been added. The filename for the generated CSV will be similar to the PDF example above (with the exception of the suffix). To populate the data for the CSV table, two additional pieces of data-- header, csv_data needs to be present in the context. 

header: a list of strings containing the headers of the CSV file.

csv_data: a list of tuples where each tuple represents a row in the resulting CSV file.

Code:

    def get_context(self, request, context):
context = super(PlannedSecurityReportPlugin, self).get_context(request, context) project = self.meta.get('project')
# data specific to this plugin
planned_tasks = self.get_planned_tasks(project)

context.update({
'planned_tasks': planned_tasks,

# data specific to CSVs
'header': [
'Task Name',
'Task ID',
'Priority'
],
'csv_data': [(task.name, task.id, task.priority)
for task in planned_tasks]
})

return context

Was this article helpful?
0 out of 0 found this helpful
Have more questions? Submit a request

Comments