django-downloadview/django_downloadview/views/object.py
2024-08-05 10:53:19 +02:00

97 lines
3.5 KiB
Python

"""Stream files that live in models."""
from django.views.generic.detail import SingleObjectMixin
from django_downloadview.exceptions import FileNotFound
from django_downloadview.views.base import BaseDownloadView
class ObjectDownloadView(SingleObjectMixin, BaseDownloadView):
"""Serve file fields from models.
This class extends :class:`~django.views.generic.detail.SingleObjectMixin`,
so you can use its arguments to target the instance to operate on:
``slug``, ``slug_kwarg``, ``model``, ``queryset``...
In addition to :class:`~django.views.generic.detail.SingleObjectMixin`
arguments, you can set arguments related to the file to be downloaded:
* :attr:`file_field`;
* :attr:`basename_field`;
* :attr:`encoding_field`;
* :attr:`mime_type_field`;
* :attr:`charset_field`;
* :attr:`modification_time_field`;
* :attr:`size_field`.
:attr:`file_field` is the main one. Other arguments are provided for
convenience, in case your model holds some (deserialized) metadata about
the file, such as its basename, its modification time, its MIME type...
These fields may be particularly handy if your file storage is not the
local filesystem.
"""
#: Name of the model's attribute which contains the file to be streamed.
#: Typically the name of a FileField.
file_field = "file"
#: Optional name of the model's attribute which contains the basename.
basename_field = None
#: Optional name of the model's attribute which contains the encoding.
encoding_field = None
#: Optional name of the model's attribute which contains the MIME type.
mime_type_field = None
#: Optional name of the model's attribute which contains the charset.
charset_field = None
#: Optional name of the model's attribute which contains the modification
# time.
modification_time_field = None
#: Optional name of the model's attribute which contains the size.
size_field = None
def get_file(self):
"""Return :class:`~django.db.models.fields.files.FieldFile` instance.
The file wrapper is model's field specified as :attr:`file_field`. It
is typically a :class:`~django.db.models.fields.files.FieldFile` or
subclass.
Raises :class:`~django_downloadview.exceptions.FileNotFound` if
instance's field is empty.
Additional attributes are set on the file wrapper if :attr:`encoding`,
:attr:`mime_type`, :attr:`charset`, :attr:`modification_time` or
:attr:`size` are configured.
"""
file_instance = getattr(self.object, self.file_field)
if not file_instance:
raise FileNotFound(
f'Field="{self.file_field}" on object="{self.object}" is empty'
)
for field in ("encoding", "mime_type", "charset", "modification_time", "size"):
model_field = getattr(self, "%s_field" % field, False)
if model_field:
value = getattr(self.object, model_field)
setattr(file_instance, field, value)
return file_instance
def get_basename(self):
"""Return client-side filename."""
basename = super().get_basename()
if basename is None:
field = "basename"
model_field = getattr(self, "%s_field" % field, False)
if model_field:
basename = getattr(self.object, model_field)
return basename
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super().get(request, *args, **kwargs)