RandomEli
RandomEli

Reputation: 1557

Making customized URL in CKAN for specific REST request

I would like to create an export button such that when a search has been finished, the export function can export search results in a csv file and download this csv file to the local machine. I have two ideas in mind, but I don't know which one is a better practice in CKAN?

  1. Give an URL such that this URL will receive the request with search_criteria and return the list of json first and then convert json in csv and download it. In template files, I just need to give an URL like <a href="{{h.url_for(request url)}}">Export</a>, but I have to implement the handle of request in plugin.py, controller.py and helpers.py.
  2. Give an URL such that handles request and convert and download, but on template file I will link the "Export" button to a request js file like <a href="request.js">Export</a>.

For both ideas, I have to add this new url in routes map and add response, convert and download in controller and plugin. I would like to know which idea will require less modification?

Upvotes: 0

Views: 548

Answers (2)

RandomEli
RandomEli

Reputation: 1557

I chose the first method and it works fine, compare to the second method, it saved my modifications to implement the export.js

You can add any search criteria in the url, template/search.html:

<a href={{h.url_for("/export", search_criteria='random string', ...)}}></a>

Then in plugin.py you can override before_map in IRoutes inferface and add the URL in before_map:

class ExportPlugin(plugins.SingletonPlugin):
    plugins.implements(plugins.IRoutes, inherit=True)

    def before_map(self, m):
        m.connect('export', '/export', 
              controller='ckanext.my_export_plugin.controller:ExportController',
              action='export')

Then in controller.py you can inherit the BaseController such that you can handle the search by package_search API and pass any of customized search criteria in facet query fq. You can also add the convert and download function in this controller:

class ExportController(base.BaseController):

    def json_to_csv(original_json):
        '''
        Other Implementation of convertion
        '''
        return csv.read()

    def export(self, data):
        '''
        Other Implementation of handling search operation
        '''
        search_results = toolkit.get_action('package_search')(data_dict=data)
        file_name = "export.csv"
        response.headers['Content-Type'] = 'application/csv'
        response.headers['Content-Disposition'] = file_name
        return json_to_csv(search_results)

After you make your own implementation, you should be able to make customized url for a REST service and completely handle the request on backend.

Upvotes: 1

D Read
D Read

Reputation: 3224

1 seems a good option to me - you need to use some of the existing python code, so javascript is going to be harder option.

The search results are produced by the package controller (dataset view from CKAN 2.9) in the search() method. It takes the query string, does some conversion to a data_dict containing search parameters (e.g. SOLR q and fq parameters). package_search logic function is called with these parameters and that returns a list of search results in the form of a JSON list. Now in the controller that JSON is used when rendering a template web page, but in your case you want to instead convert that to CSV and return that. So you could copy and paste that controller search() code (up to the render) into your own CKAN extension, serialize to CSV what you need and return it.

Or even better you could do a solution for everyone to use. Add a controller method alongside search() and factor out the code needed with the search method into a separate method that they both call. Add it as a link at the bottom of the template and submit it as a PR. :)

Upvotes: 1

Related Questions