Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Download File Url in Template

Tags:

python

django

I find tons of somewhat similar questions and no good answers for this. I have a dashboard where users upload files and it displays the ones they uploaded. I want to have them be able to click and icon or the filename and have it download. Right now it opens the file in the browser, which for images and pdf's isn't an issue as you can save from there. But when you have a docx or binary or zip, you need a download link, and it would be nice to have even for pdf's and images.

Here is my view, ignore the commented out parts:

@login_required(login_url='/dashboard-login/')
def dashboard(request):
    current_user = request.user
    current_client = request.user.client

    files = ClientUpload.objects.filter(client=current_client)    

    if request.method == 'POST':
        if request.FILES is None:
            return HttpResponseBadRequest('No Files Attached.')
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            #dz_files = request.FILES
            #for f in dz_files:
            #    new_file = ClientUpload(client=current_client, file_upload=f)
            #    new_file.save() 
            #    logger = logging.getLogger(__name__)
            #    logger.info("File uploaded from " + current_client.company)
            newfile = ClientUpload(client=current_client, file_upload=request.FILES.get('file_upload'))
            newfile.save()
            logger = logging.getLogger(__name__)
            logger.info("File uploaded from " + current_client.company)          
        else:   
            logger = logging.getLogger(__name__)
            logger.warning("Upload Failed")

        return HttpResponseRedirect(reverse('dashboard'))
    else:
        form = UploadFileForm()

    data = {'form': form, 'client': current_client, 'files': files}
    return render_to_response('dashboard.html', data, context_instance=RequestContext(request))

Here is the template, don't worry about the filters, it's just the basename and acts as os.path.basename for the name of the file. It doesn't apply to the issue whatsoever:

{% load i18n %}
{% load staticfiles %}
{% load sasite_filters %}

<table class="table">
<tr>
    <th>{% blocktrans %}Filename{% endblocktrans %}</th>
    <th>{% blocktrans %}Size (Bytes){% endblocktrans %}</th>
    <th>{% blocktrans %}Upload Time{% endblocktrans %}</th>
    <th>{% blocktrans %}Actions{% endblocktrans %}</th>
</tr>
{% for file in files %}
    {% with uploaded_file=file.file_upload %}  
 <tr>
    <th><a href="{{ MEDIA_URL }}{{ file.relative_path }}">{{ uploaded_file.name|basename }}</a></th>
    <th>{{ uploaded_file.size }}</th>
    <th>{{ file.created_at }}</th>
    <th><a href="{{ uploaded_file.url }}" id="view-btn"><i class="fa fa-search"></i></a><a href="{% url 'dashboard-delete' upload_id=file.id %}"><i class="fa fa-trash-o"></i></a></th>
    {% endwith %}
{% endfor %}
</tr>   
</table>

As you can see I have two icons, a delete and a view icon. I want to make a download icon, or make the name of the file a download link. But when I do something like <a href="{{ MEDIA_URL }}{{ file.relative_path }}">Download</a> it just opens in the browser.

relative_path is just a property on the model I could use file_upload.path without the MEDIA_URL too but it's the same thing.

I have also tried putting file:/// in front of the url and it does nothing, doesn't even open in browser.

I read that I could do something like:

response = HttpResponse(mimetype='text/plain')
response['Content-Disposition'] = 'attachment; filename="%s.txt"' % p.filename
response.write(p.body)

from Django Serving a Download File

But that is in a view, I need to do this inside of the template somehow, or find a way to do this in the view but I haven't a clue how to do that. I have considered middleware with process_response but I have no idea how to write it in this situation.

I need to take all of the files that are displayed for that user via the view's line: files = ClientUpload.objects.filter(client=current_client) and find a way to serve them as downloads rather than opening the URL in the browser.

If anyone has any experience with this situation, or knows how I can customize my template, view, or add something else to handle this it would help a lot to have a small example.

I've been stuck on this quite a while and can't seem to get it to work. Any advice would be much appreciated.

like image 571
ss7 Avatar asked Dec 02 '22 16:12

ss7


1 Answers

Is <a href="{{ your_file_url}}" download> what you need?

like image 143
brandonchinn178 Avatar answered Dec 05 '22 07:12

brandonchinn178