Serve files with Django.

Overview

django-downloadview

Jazzband GitHub Actions Coverage

django-downloadview makes it easy to serve files with Django:

  • you manage files with Django (permissions, filters, generation, ...);
  • files are stored somewhere or generated somehow (local filesystem, remote storage, memory...);
  • django-downloadview helps you stream the files with very little code;
  • django-downloadview helps you improve performances with reverse proxies, via mechanisms such as Nginx's X-Accel or Apache's X-Sendfile.

Example

Let's serve a file stored in a file field of some model:

from django.conf.urls import url, url_patterns
from django_downloadview import ObjectDownloadView
from demoproject.download.models import Document  # A model with a FileField

# ObjectDownloadView inherits from django.views.generic.BaseDetailView.
download = ObjectDownloadView.as_view(model=Document, file_field='file')

url_patterns = ('',
    url('^download/(?P<slug>[A-Za-z0-9_-]+)/$', download, name='download'),
)

Resources

Comments
  • PathDownloadView python3 compatibility

    PathDownloadView python3 compatibility

    As a relatively new django/python programmer, I am attempting to use downloadview in my project. I set up a test case from the demo, which works in python2.7, but not in python3.3. The tests are with django 1.5.4 (had similar results with 1.6 and 1.7). The results seem to suggest a problem with django, rather than downloadview, but I wanted to check here first.

    In attempting to use download_hello_world=views.PathDownloadView.as_view(path=hello_world_path)

    I got the following error


    Traceback (most recent call last): File "/usr/lib64/python3.3/wsgiref/handlers.py", line 138, in run self.finish_response() File "/usr/lib64/python3.3/wsgiref/handlers.py", line 178, in finish_response for data in self.result: File "/home/jeremiah/.virtualenvs/auto_p3_d15/lib/python3.3/site-packages/django/http/response.py", line 223, in __next__ return self.make_bytes(next(self._iterator)) File "/home/jeremiah/.virtualenvs/auto_p3_d15/lib/python3.3/site-packages/django/core/files/base.py", line 97, in __iter__ chunk_buffer = BytesIO(chunk) TypeError: 'str' does not support the buffer interface [23/Oct/2013 22:34:13] "GET /download/hello-world.txt HTTP/1.1" 500 59


    So I added a number of print() statements to downloadview to determine the point of failure, but it seems the problem is not in downloadview, but in django. So in dango/core/files/base.py::Files::__iter__() I converted chunk_buffer = BytesIO(chunk) to chunk_buffer = BytesIO(str.encode(chunk))

    And now PathDownloadView works with python 3 and 2.

    Before filing a bug in django, I wanted to check if this would be the proper fix. It seems unlikely I've discovered such a bug in django.

    Thanks.

    bug discussion 
    opened by jeremiahsavage 12
  • Update compatibility for Django 4.0

    Update compatibility for Django 4.0

    The only documented compatibility change is removing use of force_text (which was deprecated in Django 3.0) in favor of force_str (which has existed since before Django 1.11). There are also some changes in middleware because Django's MiddlewareMixin started requiring a get_response argument to the constructor.

    Fixes #187.

    opened by tari 10
  • Implement signatures for file download URLs

    Implement signatures for file download URLs

    Hi,

    tl; dr: Would this project benefit from the ability to sign download URLs (cryptographically and with expiration)?

    I thought I would open a discussion on adding download URL signatures.

    I recently implemented cryptographic authorization on top of URLs that were generated directly by the storage backend, much like with S3.

    These were served with nginx by using X-Accel and a custom view that generated serve requests to the proxy server, offloading the file serving from Django.

    The idea is fairly simple and I think many people could benefit from it. Implementation just requires

    • a Storage class mixin for specializing URL generation to add signatures in query parameters, and;
    • a decorator that validates file download URLs for the download views.

    The best thing is that download views will work with or without the signature.

    Following a naive example of the idea of the implementation. Please bear in mind that these examples are untested and would, of course, need to be further adapted for django_downloadview.

    # django_downloadview/storage.py
    
    from django.conf import settings
    from django.core.files.storage import FileSystemStorage
    from django.core.signing import BadSignature, SignatureExpired, TimestampSigner
    
    
    class SignedURLMixin(Storage):
        """ Mixin for generating signed file URLs with storage backends. Adds X-Signature query parameter to the normal URLs generated by the storage backend."""
    
        def url(self, name):
            signer = TimestampSigner()
            expiration = getattr(settings, "DOWNLOADVIEW_URL_EXPIRATION", None)
    
            path = super(SignedURLMixin, self).url(name)
            signature = signer.sign(path)
            return '{}?X-Signature={}'.format(path, signature)
    
    
    class SignedFileSystemStorage(SignedURLMixin, FileSystemStorage):
        pass
    
    # django_downloadview/decorators.py
    
    from functools import wraps
    
    from django.core.exceptions import PermissionDenied
    
    def signature_required(function):
        """ Decorator that checks for X-Signature query parameter to authorize specific user access. """
    
        @wraps
        def decorator(request, *args, **kwargs):
            signer = TimestampSigner()
            signature = request.GET.get("X-Signature")
            expiration = getattr(settings, "DOWNLOADVIEW_URL_EXPIRATION", None)
    
            try:
                signature_path = signer.unsign(signature, max_age=expiration)
            except SignatureExpired as e:
                raise PermissionDenied("Signature expired") from e
            except BadSignature as e:
                raise PermissionDenied("Signature invalid") from e
            except Exception as e:
                raise PermissionDenied("Signature error") from e
    
            if request.path != signature_path:
                raise PermissionDenied("Signature mismatch")
    
            return function(request, *args, **kwargs)
    
        return decorator
    

    Then the usage can simply be:

    # demoproject/urls.py
    
    # Django is set up with
    # DEFAULT_FILE_STORAGE='example.storage.SignedFileSystemStorage'
    
    from django.conf.urls import url, url_patterns
    from django_downloadview import ObjectDownloadView
    from django_downloadview.decorators import signature_required
    
    from demoproject.download.models import Document  # A model with a FileField
    
    # ObjectDownloadView inherits from django.views.generic.BaseDetailView.
    download = ObjectDownloadView.as_view(model=Document, file_field='file')
    
    url_patterns = ('',
        url('^download/(?P<slug>[A-Za-z0-9_-]+)/$', signature_required(download), name='download'),
    )
    
    
    {# demoproject/download/template.html #}
    {# URLs in templates are generated with the storage class URL implementation #}
    
    <a href="{{ object.file.url  }}">Click here to download.</a>
    

    The S3 Boto storage backend uses a similar approach and makes it possible to generate URLs in user templates and then authorize S3 access with those URLs. This vanilla Django approach makes it very easy to emulate that behaviour.

    Additional hardening can then be achieved with:

    • Adding random salts to signing, and expiration times to the TimestampSigner
    • Only ever using signed download links generated with the storage backend using {{ file.url }}

    This approach only lacks in that it introduces non-cacheable URLs that require slight computation to decrypt.

    Inspiration was received from Grok. You can find more information on generic URL signatures in his weblog:

    • http://grokcode.com/819/one-click-unsubscribes-for-django-apps/

    If signatures are appended to URLs with existing query parameters, a more sophisticated solution has to be used. For example:

    • https://stackoverflow.com/questions/2506379/add-params-to-given-url-in-python
    opened by aleksihakli 7
  • Use VirtualDownloadView to generate downloadable PDF file

    Use VirtualDownloadView to generate downloadable PDF file

    Basically I want to generate downloadable pdf file based on dynamic html content passed by ajax from client side. The html is in the request.GET, how can I access this value in the StringIODownloadView?

    From the official doc:

    from StringIO import StringIO
    
    from django_downloadview import VirtualDownloadView
    from django_downloadview import VirtualFile
    
    
    class StringIODownloadView(VirtualDownloadView):
        def get_file(self):
            """Return wrapper on ``StringIO`` object."""
            file_obj = StringIO(u"Hello world!\n")
            return VirtualFile(file_obj, name='hello-world.txt')
    

    I am not sure how to use the VirtualDownloadView, since there is not a demo for this. Any help is much appreciated.

    feature 
    opened by sfdye 7
  • How to use HTTPDownloadView with generic.View

    How to use HTTPDownloadView with generic.View

    I want to serve download files based on the request from an external server.I cannot fix the download url as there are many files.How to use the HTTPDownloadView with it.

    opened by apoorvaeternity 6
  • Implement Jazzband guidelines for django-downloadview

    Implement Jazzband guidelines for django-downloadview

    This issue tracks the implementation of the Jazzband guidelines for the project django-downloadview

    It was initiated by @benoitbryon who was automatically assigned in addition to the Jazzband roadies.

    See the TODO list below for the generally required tasks, but feel free to update it in case the project requires it.

    Feel free to ping a Jazzband roadie if you have any question.

    TODOs

    • [x] Fix all links in the docs (and README file etc) from old to new repo
    • [x] Add the Jazzband badge to the README file
    • [x] Add the Jazzband contributing guideline to the CONTRIBUTING.md or CONTRIBUTING.rst file
    • [x] Check if continuous testing works (e.g. Travis CI, CircleCI, AppVeyor, etc)
    • [x] Check if test coverage services work (e.g. Coveralls, Codecov, etc)
    • [x] Add jazzband account to PyPI project as maintainer role (e.g. URL: https://pypi.org/manage/project/django-downloadview/collaboration/)
    • [x] Add jazzband-bot as maintainer to the Read the Docs project (e.g. URL: https://readthedocs.org/dashboard/django-downloadview/users/)
    • [x] Add incoming GitHub webhook integration to Read the Docs project (e.g. URL: https://readthedocs.org/dashboard/django-downloadview/integrations/)
    • [x] Fix project URL in GitHub project description
    • [x] Review project if other services are used and port them to Jazzband
    • [x] Decide who is project lead for the project (if at all)
    • [x] Set up CI for Jazzband project releases if needed and open ticket if yes → Refs jazzband-roadies/help#201

    Project details

    Description Serve files with Django.
    Homepage https://django-downloadview.readthedocs.io
    Stargazers 190
    Open issues 29
    Forks 39
    Default branch master
    Is a fork False
    Has Wiki False
    Has Pages False
    opened by jazzband-bot 5
  • Avoid calling PathDownloadView.get_path() twice inside get_file()

    Avoid calling PathDownloadView.get_path() twice inside get_file()

    Overridden PathDownloadView.get_path() may contain database lookups and logging which should not be called twice if not necessary, as it was in my case. Because the acquired filename does not change inside get_file(), I replaced the duplicate call.

    bug 
    opened by rleonhardt 5
  • TypeError: int() argument must be a string or a number, not 'datetime.datetime'

    TypeError: int() argument must be a string or a number, not 'datetime.datetime'

    Hello!

    Some times i catched this exception when downloaded file. After some digging i found why.

    This happens when request has If-Modified-Since header.

    Exception raised here: https://github.com/benoitbryon/django-downloadview/blob/master/django_downloadview/views/base.py#L119

    def was_modified_since(self, file_instance, since):
            """Return True if ``file_instance`` was modified after ``since``.
            Uses file wrapper's ``was_modified_since`` if available, with value of
            ``since`` as positional argument.
            Else, fallbacks to default implementation, which uses
            :py:func:`django.views.static.was_modified_since`.
            Django's ``was_modified_since`` function needs a datetime and a size.
            It is passed ``modified_time`` and ``size`` attributes from file
            wrapper. If file wrapper does not support these attributes
            (``AttributeError`` or ``NotImplementedError`` is raised), then
            the file is considered as modified and ``True`` is returned.
            """
            try:
                return file_instance.was_modified_since(since)
            except (AttributeError, NotImplementedError):
                try:
                    modification_time = file_instance.modified_time
                    size = file_instance.size
                except (AttributeError, NotImplementedError):
                    return True
                else:
                    return was_modified_since(since, modification_time, size)
    

    because modification_time it is realy datetime object for default storage (FileSystemStorage)

    https://github.com/django/django/blob/master/django/core/files/storage.py#L324

        def modified_time(self, name):
            return datetime.fromtimestamp(os.path.getmtime(self.path(name)))
    

    I can to contribute if needed.

    bug 
    opened by zerc 4
  • DownloadView and DownloadResponse use some file wrapper

    DownloadView and DownloadResponse use some file wrapper

    In download views, we want to instanciate a download response. We currently compute file attributes (size, name, ...) and pass it to the response constructor. The more attributes (see #21), the more the response class gets complicated. Moreover we would like these attributes (see #22) to be lazy. We could implement some methods that support storages (and thus, FileField and ImageField). But then, what if someone wants to change the behaviour? He would have to override the response class.

    The response class should have some "file" (or whatever the name) attribute, and handle it via some API. Could sound like "the response's file attribute is an object with url, filename, basename, size... attributes". Then it would make it possible to have various implementations for this "file wrapper". One would use Django storages.

    Could look like django.db.models.fields.files.FieldFile, but not tied to models.

    Could help #5, #21 and #22.

    List of attributes for the file wrapper:

    • name: absolute filename in filesystem
    • url: URL where file contents live
    • size: in bytes
    • mime_type
    • encoding
    • charset
    • modification_time
    • content: iterator over file contents

    Are these attributes needed?

    • media_root: typically storage's location
    • relative_filename: filename relative to media_root
    • is_virtual: True if the file isn't on some disk, i.e. Django/Python is to compute file contents. Should be True if filename (and maybe URL too) is empty. Could also be "is_persistent", i.e. will the file live after Django processed it.
    refactoring 
    opened by benoitbryon 4
  • Replace mention of deprecated NGINX_DOWNLOAD_MIDDLEWARE_SOURCE_DIR

    Replace mention of deprecated NGINX_DOWNLOAD_MIDDLEWARE_SOURCE_DIR

    NGINX_DOWNLOAD_MIDDLEWARE_MEDIA_ROOT is deprecated in favor of NGINX_DOWNLOAD_MIDDLEWARE_SOURCE_DIR

    https://github.com/jazzband/django-downloadview/blob/563b2a4f7b354cb930aa7067e6e1341dbb34f5e7/django_downloadview/nginx/middlewares.py#L120-L121

    opened by johnthagen 3
  • Proposal to move django-downloadview to JazzBand.

    Proposal to move django-downloadview to JazzBand.

    • [x] Add Jazzband a badge in the readme
    • [x] Make sure there is a CONTRIBUTING documentation
    • [x] Add the contributing JazzBand header

    Full guidelines: https://jazzband.co/about/guidelines

    • [ ] Open an issue to ask roadies to configure a travis rule for deployment to pypi.
    opened by Natim 3
  • How to use django-downloadview for ensuring only authenticated users can access media files?

    How to use django-downloadview for ensuring only authenticated users can access media files?

    I have similar question as #129

    the only difference is that I'm using nginx. I'm not so interested about performance, but only that I want to ensure only authenticated users can access media files.

    That's all.

    The documentation I have tried reading e,g, https://django-downloadview.readthedocs.io/en/latest/optimizations/nginx.html?highlight=media#setup-xaccelredirect-middlewares but still none the wiser.

    They seem to emphasize for performance. Not authentication or privacy.

    Can help?

    opened by simkimsia 0
  • Upgrade GitHub Actions

    Upgrade GitHub Actions

    https://github.com/actions/checkout/releases https://github.com/actions/setup-python/releases https://github.com/actions/cache/releases https://github.com/codecov/codecov-action/releases

    opened by cclauss 0
  • Signal/event once file has been downloaded?

    Signal/event once file has been downloaded?

    When applications want to indicate to users whether they have seen/downloaded a document or not, this would probably happen with the help of a boolean has_been_downloaded model field on the corresponding model.

    To actually turn this field true once a document has been downloaded, it would be really helpful if the package could send a signal, offer a hook, that gets triggered, when a document was shipped successfully.

    I guess this could be implemented with some custom code in a custom view that wraps one of the package views.

    DRF example:

        @action(detail=True)
        def download(self, request, pk):
            document = self.get_object()
    
            # When the owner downloads the document, we want to update the
            # has_been_downloaded field correspondingly
            if document.has_been_downloaded is False:
                document.has_been_downloaded = True
                document.save()
    
            return ObjectDownloadView.as_view(
                model=Document,
            )(request, pk=pk)
    

    But this would always happen before the actual download code runs and therefore, when the download somehow fails, data would wrongly be changed in the model.

    opened by devidw 0
  • Very slow download speed from `ObjectDownloadView`

    Very slow download speed from `ObjectDownloadView`

    I have an ObjectDownloadView that is serving very large files (200MB - 2GB). I've observed that the download speed is very slow, even when pulling downloads over localhost where no actual network is involved at all. I must authenticate the file downloads (not shown the example below), which is why I must use django-downloadview rather than serving them statically.

    I cannot use NGINX acceleration due to:

    • #177

    My endpoint looks something like:

    class MyModelObjectDownloadView(ObjectDownloadView):
        model_class = MyModel
        file_field = "model"
        basename_field = "filename"
    

    The Model:

    class MyModel(models.Model):
        MODEL_UPLOAD_TO_DIR = "models"
        model = models.FileField(upload_to=MODEL_UPLOAD_TO_DIR)
        filename = models.TextField()
    

    URLs:

    urlpatterns = [
        ...
        path(
            f"media/{MyModel.MODEL_UPLOAD_TO_DIR}/<int:pk>/",
            MyModelObjectDownloadView.as_view(),
            name=SurfaceModel.IMAGE_UPLOAD_TO_DIR,
        ),
    ]
    

    I've tested downloading the file using a variety of clients over localhost (also running locally on mac and also within a Linux Docker container) and they all show a similar result:

    • httpx
    • Chrome
    • curl
    $ curl http://localhost:8000/media/models/1/ --output out.bin
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100  118M  100  118M    0     0  5398k      0  0:00:22  0:00:22 --:--:-- 5663k
    

    This corresponds to about 40Mbps, which seemed very slow for a localhost pull. I also see the python executable running at about 100% CPU, as if it's CPU rather than I/O bound?

    Is there something about how django-downloadview streams or chunks the file that contributes to why this is so slow?

    Are there any configuration settings to speed up serving files natively from django-downloadview?

    opened by johnthagen 2
  • Use Django's built-in FileResponse to address security issue

    Use Django's built-in FileResponse to address security issue

    Django recently released a patch that addresses CVE-2022-36359

    I am concerned that since this library does not use Django's FileResponse, it may be vulnerable to a similar type of attack and will not benefit from Django's patch.

    After copying test case from the django patch and running it against DownloadView, I noticed that it does not pass so it is possible that the DownloadView is not as secure since it does not escape file names.

    opened by mick88 1
  • Add Async Support

    Add Async Support

    Currently, the DownloadView operates as a sync view. It's very possible (and much more efficient) to do everything async.

    File reading will have to be done via aiofile in order to not break the ASGI event queue though. After this change, Django versions will need to be limited to 3.1+

    feature 
    opened by Archmonger 2
Releases(2.3.0)
An automatic django's update checker and MS teams notifier

Django Update Checker This is small script for checking any new updates/bugfixes/security fixes released in django News & Events and sending correspon

prinzpiuz 4 Sep 26, 2022
Developer-friendly asynchrony for Django

Django Channels Channels augments Django to bring WebSocket, long-poll HTTP, task offloading and other async support to your code, using familiar Djan

Django 5.5k Jan 06, 2023
A CTF leaderboard for the submission of flags during a CTF challenge. Built using Django.

🚩 CTF Leaderboard The goal of this project is to provide a simple web page to allow the participants of an CTF to enter their found flags. Also the l

Maurice Bauer 2 Jan 17, 2022
A Minimalistic Modern Django Boilerplate

A Minimalistic Modern Django Boilerplate This boilerplate is mainly for educational purposes. It is meant to be cloned as a starter code for future tu

Jonathan Adly 21 Nov 02, 2022
Django Advance DumpData

Django Advance Dumpdata Django Manage Command like dumpdata but with have more feature to Output the contents of the database from given fields of a m

EhsanSafir 7 Jul 25, 2022
Exploit Discord's cache system to remote upload payloads on Discord users machines

Exploit Discord's cache system to hide payloads PoC Remote upload embedded payload from image using EOF to Discord users machines through cache. Depen

cs 169 Dec 20, 2022
This is a simple Todo web application built Django (back-end) and React JS (front-end)

Django REST Todo app This is a simple Todo web application built with Django (back-end) and React JS (front-end). The project enables you to systemati

Maxim Mukhin 5 May 06, 2022
A simple demonstration of integrating a sentiment analysis tool in a django project

sentiment-analysis A simple demonstration of integrating a sentiment analysis tool in a django project (watch the video .mp4) To run this project : pi

2 Oct 16, 2021
Ugly single sign-on for django projects only

django-usso Ugly single sign-on for django projects only. Do you have many django apps with different users? Do you want to use only one of those apps

Erwin Feser 1 Mar 01, 2022
A Blog Management System Built with django

Blog Management System Backend use: Django Features Enhanced Ui

Vishal Goswami 1 Dec 06, 2021
Exemplo de biblioteca com Django

Bookstore Exemplo de biblioteca feito com Django. Este projeto foi feito com: Python 3.9.7 Django 3.2.8 Django Rest Framework 3.12.4 Bootstrap 4.0 Vue

Regis Santos 1 Oct 28, 2021
Django app for handling the server headers required for Cross-Origin Resource Sharing (CORS)

django-cors-headers A Django App that adds Cross-Origin Resource Sharing (CORS) headers to responses. This allows in-browser requests to your Django a

Adam Johnson 4.8k Jan 03, 2023
A ToDO Rest API using Django, PostgreSQL and Docker

This Rest API uses PostgreSQL, Docker and Django to implements a ToDo application.

Brenno Lima dos Santos 2 Jan 05, 2022
Dynamic, database-driven Django forms

Django Dataforms django-dataforms is a wrapper for the Django forms API that lets you dynamically define forms in a database, rather than hard-coding

35 Dec 16, 2022
Fully reponsive Chat Application built with django, javascript, materialUi, bootstrap4, html and css.

Chat app (Full Stack Frameworks with Django Project) Fully reponsive Chat Application built with django, javascript, materialUi, bootstrap4, html and

1 Jan 19, 2022
Template de desarrollo Django

Template de desarrollo Django Python Django Docker Postgres Nginx CI/CD Descripción del proyecto : Proyecto template de directrices para la estandariz

Diego Esteban 1 Feb 25, 2022
Alt1-compatible widget host for RuneScape 3

RuneKit Alt1-compatible toolbox for RuneScape 3, for Linux and macOS. Compatibility macOS installation guide Running This project use Poetry as packag

Manatsawin Hanmongkolchai 75 Nov 28, 2022
Probably the best abstract model / admin for your tree based stuff.

django-treenode Probably the best abstract model / admin for your tree based stuff. Features Fast - get ancestors, children, descendants, parent, root

Fabio Caccamo 360 Jan 05, 2023
Notes-Django: an advanced project to save notes in Django. where users are able to Create, Read, Update and Delete their notes.

An advanced software to keep you notes. It allows users to perform CRUD operations on theirs Notes. Was implemented Authorization and Authentication

Edilson Pateguana 1 Feb 05, 2022
A BitField extension for Django Models

django-bitfield Provides a BitField like class (using a BigIntegerField) for your Django models. (If you're upgrading from a version before 1.2 the AP

DISQUS 361 Dec 22, 2022