Generate the response for a Download CSV button from data within the context dict

    The CSV data must be in one of these places/formats:

    * context as a list of lists of python values (strings for headers in first list)
    * context['data']['d3data'] as a string in json format (python) for a list of lists of repr(python_value)s
    * context['data']['cases'] as a list of lists of python values (strings for headers in first list)
    * context['data']['cases'] as a django queryset or iterable of model instances (list, tuple, generator)

    If the input data is a list of lists (table) that has more columns that rows it will be trasposed before being processed

def csv_response_from_context(context=None, filename=None, field_names=None, null_string='', eval_python=True):
    """Generate the response for a Download CSV button from data within the context dict

    The CSV data must be in one of these places/formats:

    * context as a list of lists of python values (strings for headers in first list)
    * context['data']['d3data'] as a string in json format (python) for a list of lists of repr(python_value)s
    * context['data']['cases'] as a list of lists of python values (strings for headers in first list)
    * context['data']['cases'] as a django queryset or iterable of model instances (list, tuple, generator)

    If the input data is a list of lists (table) that has more columns that rows it will be trasposed before being processed
    """
    filename = filename or context.get('filename') or 'table_download.csv'
    field_names = field_names or context.get('field_names', [])
    # FIXME: too slow!
    if field_names and all(field_names) and all(all(c in (string.letters + string.digits + '_.') for c in s) for s in field_names):
        eval_python=False

    data = context

    # find the data table within the context dict. should be named 'data.cases' or 'data.d3data'
    if not (isinstance(data, (tuple, list)) and isinstance(data[0], (tuple, list))):
        data = json.loads(data.get('data', {}).get('d3data', '[[]]'))
        if not data or not any(data):
            data = context.get('data', {}).get('cases', [[]])

    if not isinstance(data, (list, tuple)) or not isinstance(data[0], (list, tuple)):
        data = table_generator_from_list_of_instances(data, field_names=field_names, eval_python=eval_python)

    try:
        if len(data) < len(data[0]):
            data = util.transposed_lists(data)  # list(list(row) for row in data)
    except TypeError:
        # no need to transpose if a generator was provided instead of a list or tuple (anything with a len attribute)
        pass

    # Create the HttpResponse object with the appropriate CSV header.
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="%s"' % filename

    writer = csv.writer(response)
    for row in data:
        newrow = []
        for s in row:
            try:
                newrow.append(s.encode('utf-8')) #handles strings, unicodes, utf-8s
            except AttributeError:  #will happen when we try to encode a class object or number
                newrow.append(s)
            except: #not sure it ever will be touched.
                newrow.append(unicode(s))
        writer.writerow(newrow)
    return response