user11603936
user11603936

Reputation: 79

How to download uploaded files through a link in Django

I am uploading a file and saving it on a folder outside the media folder. I want to add a download link in a template to be able to download the file directly. I am not sure what to add in the URL, if I should add something

I tried this in the template it says URL not found

<a href="{{data.tar_gif.url}}"> Download File</a>

views.py

def uploaddata(request):
        if request.user.is_authenticated:

                if request.method == 'POST':
                        
                        form = uploadform(request.POST, request.FILES)
                        if form.is_valid():
                                form.save()
                                
                                return redirect('file_list')
                else:
                        form = uploadmetaform()
                        
                return render(request, 'uploaddata.html', {
                        'form': form
                })
        else:
                return render(request, 'home.html')

HTML page

<tbody>
    {% for data in dataset %}
    <tr>
        <td>{{data.path_id}}</td>
        <td>{{ data.tar_gif }}</td>
        
        <td>
            <a href="{{data.document.url}}"> Download File</a>
                
            
            </td>
    </tr>
    {% endfor %}
</tbody>

models.py

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)

    Assigned_Group= models.CharField(max_length=500, choices=Group_choices, default='Please Select')

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

upload file

def nice_user_folder_upload(instance, filename):
    extension = filename.split(".")[-1]
    return (
        f"{instance.user_profile.Assigned_Group}/{filename}"
    )

class uploadmeta(models.Model):

    path = models.ForeignKey(Metadataform, on_delete=models.CASCADE)

    user_profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, null=True, verbose_name='Username')
    

    document = models.FileField(upload_to=nice_user_folder_upload, verbose_name="Dataset") # validators=[FileExtensionValidator(allowed_extensions=['tar', 'zip'])]

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

Upvotes: 2

Views: 7392

Answers (3)

MOhammad.Isaac.Ahmadi
MOhammad.Isaac.Ahmadi

Reputation: 379

1.settings.py:

MEDIA_DIR = os.path.join(BASE_DIR,'media')
#Media
MEDIA_ROOT = MEDIA_DIR
MEDIA_URL = '/media/'

2.urls.py:

from django.conf.urls.static import static
urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)

3.in template:

<a href="{{ file.url }}" download>Download File.</a>

Work and test in django >=3

for more detail use this link: https://youtu.be/MpDZ34mEJ5Y

Upvotes: 4

Mariano
Mariano

Reputation: 31

Look at this post: How to serve downloadable files using Django (Chris Gregori) ?

Maybe a better way to not expose the path of the files, even the names if you do want to do that. I do not like the idea to show the structure of the paths to users. Other things you can accomplish with this is to validate who can download the files if you check the request.user with your database for every file is served, and it is pretty simple.

Basically, the publication refers to using the xsendfile module so django generates the path to the file (or the file itself), but the actual file serving is handled by Apache/Lighttpd. Once you've set up mod_xsendfile, integrating with your view takes a few lines of code:"

from django.utils.encoding import smart_str

response = HttpResponse(mimetype='application/force-download') # mimetype is replaced by content_type for django 1.7
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)

response['X-Sendfile'] = smart_str(path_to_file)
# It's usually a good idea to set the 'Content-Length' header too.
# You can also set any other required headers: Cache-Control, etc.
return response

As I said before, I do not like the idea of having published the path to the file.

With this pointer to the information, you can research and get this working.

Hope it works for you.

Upvotes: 0

ShravaN
ShravaN

Reputation: 126

Actually simple way of doing it by using html download attribute the way you achieve this is by

<a href="{{data.document.url}}" download> Download File</a>

or you also use :

<a href="{{ data.document.url }}" download="{{ data.document.url }}"> Download File</a>

Upvotes: 6

Related Questions