'Provide path of the file to be downloaded in django

views.py

def download(request, path):
    file_path = os.path.join(settings.MEDIA_ROOT, path)
    if os.path.exists(file_path):
        with open(file_path, 'rb') as fh:
            response = HttpResponse(fh.read(), content_type="application/pdf")
            response['Content-Disposition'] = 'inline; filename=' + os.path.basename(file_path)
            return response
    raise Http404

urls.py

from unicodedata import name
from django.urls import path
from Profile import views

urlpatterns = [
  ...
  path('download/<str:path>/', views.download, name="download"),
]

models.py

from django.db import models
from django.contrib.auth.models import User
from taggit.managers import TaggableManager

# Create your models here.
class ProfileModel(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(null=True)
    address = models.CharField(max_length=255 , null=True)
    image = models.ImageField(null=True, blank=True)

    def __str__(self):
        return str(self.user)

template

{% extends 'base.html' %}

{% block content %}
Welcome, {{request.user.username}}
<table>
    <tr>
        <th>First Name: </th>
        <th>{{user.first_name}}</th>
    </tr>
    <tr>
        <th>Last Name: </th>
        <th>{{user.last_name}}</th>
    </tr>
    <tr>
        <th>Email: </th>
        <th>{{user.email}}</th>
    </tr>
    <tr>
        <th>Image: </th>
        {% if user.image %}
        <!-- here is the error -->
        <th><a href="{% url 'download' user.image.url%}"><img src=" {{user.image.url}}" alt="IMage...." style="object-fit: cover;
            border-radius: 50%;
            height: 200px;
            width: 200px;"></a></th>
        {% endif %}
    </tr>
    <tr>
        <th>Address: </th>
        <th>{{user.address}}</th>
    </tr>
    <tr>
        <th>Bio: </th>
        <th>{{user.bio|linebreaks}}</th>
    </tr>
</table>

MEDIA_URL = '/images/'

MEDIA_ROOT = os.path.join(BASE_DIR, 'static/images')

The problem is with the path I have provided for the file to be downloaded in the template. I don't know the correct way to give the required path of the file to the download view. Error - "Reverse for 'download' with arguments '('/images/Nitro_Wallpaper_5000x2813_Vm2jvWw.jpg',)' not found. 1 pattern(s) tried: ['Profile/download/(?P[^/]+)/\Z']". But "Nitro_Wallpaper_5000x2813_Vm2jvWw.jpg" is present in my images folder.



Solution 1:[1]

views.py

def download(request, filename):
    path = os.path.join(settings.MEDIA_ROOT, filename)
    file_path = os.path.join(settings.BASE_DIR, path)
    if os.path.exists(file_path):
        with open(file_path, 'rb') as fh:
            response = HttpResponse(fh.read(), content_type="application/octet-stream")
            response['Content-Disposition'] = 'inline; filename=' + os.path.basename(file_path)
            return response
    raise Http404

template

{% extends 'base.html' %}

{% block content %}
Welcome, {{request.user.username}}
<table>
    <tr>
        <th>First Name: </th>
        <th>{{user.first_name}}</th>
    </tr>
    <tr>
        <th>Last Name: </th>
        <th>{{user.last_name}}</th>
    </tr>
    <tr>
        <th>Email: </th>
        <th>{{user.email}}</th>
    </tr>
    <tr>
        <th>Image: </th>
        {% if user.image %}
        <th><a href="{% url 'download' user.image%}"><img src="{{user.image.url}}" alt="IMage...." style="object-fit: cover;
            border-radius: 50%;
            height: 200px;
            width: 200px;"></a></th>
        {% endif %}
    </tr>
    <tr>
        <th>Address: </th>
        <th>{{user.address}}</th>
    </tr>
    <tr>
        <th>Bio: </th>
        <th>{{user.bio|linebreaks}}</th>
    </tr>
</table>

Providing just the file name in the function parameter and set the filepath in the download view. Also set the content_type as octet/stream.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Vansh_Chaudhary