0c836454b2
Previously template.render() takes Context or RequestContext object
but after Django 1.8 the method takes a dict and request as separate
arguments. The old way will be dropped in Django 1.10.
This commit update the usage based on the Django 1.8 release notes [1].
commit 95d78a140f
addresses this
deprecations but it turns out all similar places are not switched.
I searched the code base more carefully and found more.
I hope this clean up all of them.
After this change, extra_context which was passed to (Request)Context
previously is no longer available in HttpResponse object.
Volume unit test is tightly coupled with the context information
and checks rendered actions using the context. Thus the corresponding
tests no longer work. Since we can use only HttpResponse.content
(which is a rendered HTML), the new tests just check various strings
like ID, link and label of a specific action.
This is tricky, but this is now the only thing we can do.
[1] https://docs.djangoproject.com/en/1.8/ref/templates/upgrading/#get-template-and-select-template
Change-Id: I350c22dc3d7db7b93ca4b823dac1e3d88beef1a7
143 lines
4.5 KiB
Python
143 lines
4.5 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from __future__ import division
|
|
|
|
from csv import DictWriter
|
|
from csv import writer
|
|
|
|
|
|
from django.http import HttpResponse
|
|
from django.http import StreamingHttpResponse
|
|
from django import template as django_template
|
|
import six
|
|
|
|
from six import StringIO
|
|
|
|
|
|
class CsvDataMixin(object):
|
|
|
|
"""CSV data Mixin - provides handling for CSV data.
|
|
|
|
.. attribute:: columns
|
|
|
|
A list of CSV column definitions. If omitted - no column titles
|
|
will be shown in the result file. Optional.
|
|
"""
|
|
def __init__(self):
|
|
self.out = StringIO()
|
|
super(CsvDataMixin, self).__init__()
|
|
if hasattr(self, "columns"):
|
|
columns = [self.encode(col) for col in self.columns]
|
|
self.writer = DictWriter(self.out, columns)
|
|
self.is_dict = True
|
|
else:
|
|
self.writer = writer(self.out)
|
|
self.is_dict = False
|
|
|
|
def write_csv_header(self):
|
|
if self.is_dict:
|
|
try:
|
|
self.writer.writeheader()
|
|
except AttributeError:
|
|
# For Python<2.7
|
|
self.writer.writerow(dict(zip(
|
|
self.writer.fieldnames,
|
|
self.writer.fieldnames)))
|
|
|
|
def write_csv_row(self, args):
|
|
if self.is_dict:
|
|
self.writer.writerow(dict(zip(
|
|
self.writer.fieldnames, [self.encode(col) for col in args])))
|
|
else:
|
|
self.writer.writerow([self.encode(col) for col in args])
|
|
|
|
def encode(self, value):
|
|
value = six.text_type(value)
|
|
if six.PY2:
|
|
# csv and StringIO cannot work with mixed encodings,
|
|
# so encode all with utf-8
|
|
value = value.encode('utf-8')
|
|
return value
|
|
|
|
|
|
class BaseCsvResponse(CsvDataMixin, HttpResponse):
|
|
|
|
"""Base CSV response class. Provides handling of CSV data."""
|
|
|
|
def __init__(self, request, template, context, content_type, **kwargs):
|
|
super(BaseCsvResponse, self).__init__()
|
|
self['Content-Disposition'] = 'attachment; filename="%s"' % (
|
|
kwargs.get("filename", "export.csv"),)
|
|
self['Content-Type'] = content_type
|
|
self.context = context
|
|
self.header = None
|
|
if template:
|
|
# Display some header info if provided as a template
|
|
header_template = django_template.loader.get_template(template)
|
|
self.header = header_template.render(self.context, request)
|
|
|
|
if self.header:
|
|
self.out.write(self.encode(self.header))
|
|
|
|
self.write_csv_header()
|
|
|
|
for row in self.get_row_data():
|
|
self.write_csv_row(row)
|
|
|
|
self.out.flush()
|
|
self.content = self.out.getvalue()
|
|
self.out.close()
|
|
|
|
def get_row_data(self):
|
|
return []
|
|
|
|
|
|
class BaseCsvStreamingResponse(CsvDataMixin, StreamingHttpResponse):
|
|
|
|
"""Base CSV Streaming class. Provides streaming response for CSV data."""
|
|
|
|
def __init__(self, request, template, context, content_type, **kwargs):
|
|
super(BaseCsvStreamingResponse, self).__init__()
|
|
self['Content-Disposition'] = 'attachment; filename="%s"' % (
|
|
kwargs.get("filename", "export.csv"),)
|
|
self['Content-Type'] = content_type
|
|
self.context = context
|
|
self.header = None
|
|
if template:
|
|
# Display some header info if provided as a template
|
|
header_template = django_template.loader.get_template(template)
|
|
self.header = header_template.render(self.context, request)
|
|
|
|
self._closable_objects.append(self.out)
|
|
|
|
self.streaming_content = self.get_content()
|
|
|
|
def buffer(self):
|
|
buf = self.out.getvalue()
|
|
self.out.truncate(0)
|
|
return buf
|
|
|
|
def get_content(self):
|
|
if self.header:
|
|
self.out.write(self.encode(self.header))
|
|
|
|
self.write_csv_header()
|
|
yield self.buffer()
|
|
|
|
for row in self.get_row_data():
|
|
self.write_csv_row(row)
|
|
yield self.buffer()
|
|
|
|
def get_row_data(self):
|
|
return []
|