VirtualDownloadView¶
VirtualDownloadView
serves files that do not live on disk.
Use it when you want to stream a file which content is dynamically generated
or which lives in memory.
It is all about overriding VirtualDownloadView.get_file()
method so that
it returns a suitable file wrapper...
Note
Current implementation does not support reverse-proxy optimizations, because content is actually generated within Django, not stored in some third-party place.
Base options¶
VirtualDownloadView
inherits from
DownloadMixin
, which has various
options such as basename
or attachment
.
Serve text (string or unicode) or bytes¶
Let’s consider you build text dynamically, as a bytes or string or unicode
object. Serve it with Django’s builtin
ContentFile
wrapper:
from django.core.files.base import ContentFile
from django_downloadview import VirtualDownloadView
class TextDownloadView(VirtualDownloadView):
def get_file(self):
"""Return :class:`django.core.files.base.ContentFile` object."""
return ContentFile(b"Hello world!\n", name='hello-world.txt')
Serve StringIO¶
StringIO
object lives in memory. Let’s wrap it in some
download view via VirtualFile
:
from six import StringIO
from django_downloadview import VirtualDownloadView
from django_downloadview import VirtualFile
class StringIODownloadView(VirtualDownloadView):
def get_file(self):
"""Return wrapper on ``six.StringIO`` object."""
file_obj = StringIO(u"Hello world!\n")
return VirtualFile(file_obj, name='hello-world.txt')
Stream generated content¶
Let’s consider you have a generator function (yield
) or an iterator object
(__iter__()
):
def generate_hello():
yield u'Hello '
yield u'world!'
yield u'\n'
Stream generated content using VirtualDownloadView
,
VirtualFile
and
BytesIteratorIO
:
from django_downloadview import VirtualDownloadView
from django_downloadview import VirtualFile
from django_downloadview import TextIteratorIO
class GeneratedDownloadView(VirtualDownloadView):
def get_file(self):
"""Return wrapper on ``StringIteratorIO`` object."""
file_obj = TextIteratorIO(generate_hello())
return VirtualFile(file_obj, name='hello-world.txt')
API reference¶
-
class
django_downloadview.views.virtual.
VirtualDownloadView
(**kwargs)¶ Bases:
django_downloadview.views.base.BaseDownloadView
Serve not-on-disk or generated-on-the-fly file.
Override the
get_file()
method to customize file wrapper.-
was_modified_since
(file_instance, since)¶ Delegate to file wrapper’s was_modified_since, or return True.
This is the implementation of an edge case: when files are generated on the fly, we cannot guess whether they have been modified or not. If the file wrapper implements
was_modified_since()
method, then we trust it. Otherwise it is safer to suppose that the file has been modified.This behaviour prevents file size to be computed on the Django side. Because computing file size means iterating over all the file contents, and we want to avoid that whenever possible. As an example, it could reduce all the benefits of working with dynamic file generators... which is a major feature of virtual files.
-