How can I download the file linked with the post?

Viewed 65

I'm quite new to using Django and I am trying to develop a website where the user can download file at the end of the post. Post model:

class Article(models.Model):
    title = models.CharField(max_length=30)
    content = models.TextField()
    pub_date = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    file = models.FileField(upload_to='code_files/')


    def __str__(self):
        return self.title

I have a views:

def download(request):
    response = HttpResponse(open(f"media/code_files/tests.py", 'rb').read())
    response['Content-Type'] = 'text/plain'
    response['Content-Disposition'] = f'attachment; filename=tests.py'
    return response

How can I download the file linked with the post?

3 Answers

From Dajngo docs FileResponse is a subclass of StreamingHttpResponse optimized for binary files.

import os

from django.http import FileResponse
from django.views.decorators.http import require_POST

@require_POST    
def download(request):
    article = Article.objects.get(id=1)
    fullpath = article.file.path
    if not os.path.exists(fullpath):
        raise Http404('{0} does not exist'.format(fullpath))
    return FileResponse(
        open(fullpath, 'rb'), as_attachment=True,
        filename=article.file.name)

Assuming that you passed the Article object to your template from your views as a context.

context = {
    'article' = article_obj,
}

In your HTML, you need to use the embed tag and the url of the FileField of the Article object.

<embed src="{{article.file.url}}" width="500" height="200">

You shouldn't need to write another view just to download the file. Just have the article in your context in the view where you want to show the link to download:

context = {'article': Article.objects.first()}

Make sure that you have also added your media URL in your settings:

MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")

and project urls.py:

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Then, for your article model, give each article a formatted file url:

class Article(models.Model):

    @property
    def formatted_file_url(self):
        if self.file:
            return settings.MEDIA_URL + self.file.url
        else:
            return 'No url'

Download with:

<a href="{{ article.formatted_file_url }}" download>
Related