1

I'm trying to make a link to a file path on a Windows server downloadable to the user after they click the file link.

My app displays entries from a result of searching a ticket model. The results on the page include items like: Ticket number, description, status and a link to a flat file (that is stored on a Windows server network share drive; starting with \server.name\folder A\folder B\folder C\file to download.txt

Note

  • \server.name, \folder A and \folder B are a constant
  • \folder C (as well as the file to download are dynamic (they location and file name will change)
  • users will NOT be uploading files. All files that are downloadable - are already saved to a Windows share.

On the display page/template.html I can list all my values in a table (even a link the the file I'd like to download). However, when I hover over the link at the bottom of the browser I see file://server.name/folder A/folder B\\folder C\\file to download.txt. Yes, the last "slash" is a forward slash while all the others are back slashes (not sure why they are changing?)

When I pass the file address to the template it is formatted like : \\server.name\\folder A\\folder B\\folder C\\file to download.txt (I can see that in testing when I just displayed the filepath on the page.

How do you make the link to a file path on a Windows server downloadable to users that wish to download the file?

.html

<body>

<h1><p>Ticket Number: {{ thisincident.IncidentID }}</p></h1>
<h3>Description: {{ thisincident.Description }}</h3>
<h4><p>Full Description</h4> {{ thisincident.FullDescription | linebreaks }}</p>

    
    
       Journal Entry #
       Date
       Person
       Journal Entry
       File Name
    
    
    
    {% for f in je %}
    
       {{ f.JE }}
       {{ f.Date }} 
       {{ f.resource }}
       {{ f.entry | linebreaks }}
       <a href="{{ f.Location }}">Download</a>
    
    {% endfor %}

view.py


def ticket_view(request, IncidentID):
    file_contents = []
    thisincident = ticket.objects.get(id=IncidentID)
    for root, dirs, files in os.walk(thisincident.LocationPath):
        for file in files:
            if not file == 'manifest.json':
                path_file = os.path.join(root, file)
                path_file = path_file.replace(thisincident.LocationPath + "\\", "")
                file_contents.append(path_file)
    log_list = parseJElog(thisincident.logfiletoparse)

    data = {
        "thisincident": thisincident,
        "result": file_contents,
        "je":log_list
    }
    return render(request, "ticket.html", data)

urls.py

urlpatterns = [
    url(r'^homepage/$', views.home, name='home'),
    url(r'^tickets/$', views.tickets, name='tickets'),
    url(r'^ticket/(?P<IncidentID>\d+)$', views.ticket_view, name='ticket'),
]
if settings.DEBUG:
    urlpatterns+=static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

settings.py

MEDIA_BASE_ROOT = "\\server.name\\folder A\\folder B"
MEDIA_ROOT = os.path.join(MEDIA_BASE_ROOT, "\\folder B\\")
MEDIA_URL = ''

enter image description here

I'm fairly new to Django so any help will be much appreciated.

Ivan Starostin
  • 8,798
  • 5
  • 21
  • 39

1 Answers1

0

I also had a similar issue before. You can follow these steps to solve this. I will split the logic into two functions to make this straightforward and easy.

1, display the tickets

def ticket_view(request, IncidentID):
    thisincident = ticket.objects.get(id=IncidentID)
    log_list = parseJElog(thisincident.logfiletoparse)

    data = {
        "thisincident": thisincident,
        "je": log_list
    }
    return render(request, "ticket.html", data)

2, download the file

import os
from django.http import FileResponse

def download_file(request, file_path):
    file_name = os.path.basename(file_path)
    file = open(file_path, 'rb')
    response = FileResponse(file)
    response['Content-Disposition'] = f'attachment; filename="{file_name}"'
    return response

I think this is the code you need, the issue your face can be simply solved by using the os.path or you can use pathlib. here we are passing the file path as an argument into the function and it opens the file in binary mode, creates a FileResponse with the file content, and sets the Content-Disposition header to specify the filename for the user to download it.

Content-Disposition header is an optional header by the way.

more about Content-Disposition

3, update your URLs according to the functions we define above.

4, update your template.

{% for f in je %}
        {{ f.JE }}
        {{ f.Date }} 
        {{ f.resource }}
        {{ f.entry | linebreaks }}
        <a href="{% url 'download_file' file_path=f.Location %}">Download</a>
    {% endfor %}

5, update your settings

MEDIA_URL = '/media/' # edit this to your requirements 
MEDIA_ROOT = '\\server.name\folder A\folder B\folder C'  # Windows server path

# make sure that you also serving media files in the URL
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

I hope this solution helps you.

  • Thank you for the help and detail in this solution. I used it exactly as you presented and it worked! Thanks again. – Gary Swartz Jul 09 '23 at 16:19