如何修复DataTable列中PDF/DOCX文件下载失败问题?
Let's work through your download issue step by step—there are a couple of small misconfigurations in your models, views, and frontend code that are causing the failures.
1. Fix the FileField Configuration in Models
First, your report_path field is set up incorrectly. The upload_to parameter should be a relative path from MEDIA_ROOT, not an absolute path. When you use settings.MEDIA_ROOT+'/%Y/%m/%d', you're storing the full absolute path in the database, which isn't what Django expects for FileFields.
Update your models.py:
report_path = models.FileField(upload_to='%Y/%m/%d')
Django will automatically prepend MEDIA_ROOT to this path when storing files, so your uploaded files will go to D:/uploads/YYYY/MM/DD/ as intended. The database will store the relative path (like 2024/05/20/my_report.pdf) instead of the full absolute path.
2. Update the Download View to Handle Media Files
Your current view tries to open the file using the filename directly, but that's just the relative path from the database. You need to combine it with MEDIA_ROOT to get the full file path. Also, using Django's FileResponse is more efficient for file downloads, and you should add error handling for missing files.
Update your views.py:
from django.http import FileResponse, Http404 import os from django.conf import settings def downloads(request, filename): # Combine MEDIA_ROOT with the relative filename from the database file_pathname = os.path.join(settings.MEDIA_ROOT, filename) # Check if the file exists to avoid server errors if not os.path.exists(file_pathname): raise Http404("File not found") # Use FileResponse for better performance with large files response = FileResponse(open(file_pathname, 'rb'), content_type='application/octet-stream') # Extract just the filename (not the full path) for the download prompt actual_filename = os.path.basename(file_pathname) response['Content-Disposition'] = f'attachment; filename="{actual_filename}"' return response
3. Fix the Frontend DataTable Render Function
The big issue here is that you're trying to use Django's {% url %} template tag inside JavaScript that runs on the frontend. Since the DataTable is loaded via AJAX, the Django template engine never parses that {% url %} tag—it gets sent as plain text to the browser, resulting in an invalid URL.
Instead, construct the download URL directly in the render function using the base URL of your downloads endpoint, and append the report_path value from the AJAX response.
Update your frontend code:
$(document).ready(function() { var table = $('#sample').DataTable({ "serverSide": true, "ajax": "/api/sample/?format=datatables", "columns": [ {"data": "hospital_name"}, {"data": "report_path", "render": function(data, type, row, meta){ // Construct the download URL by appending the report_path to the downloads endpoint return `<a href="/downloads/${encodeURIComponent(data)}">Download</a>`; }} ] }); });
Using encodeURIComponent() ensures that any special characters in the file path (like slashes or spaces) are properly encoded for the URL.
4. Verify Your URL Pattern & Media Serving
Your current URL pattern for downloads looks okay, but just double-check that it's correctly capturing the full filename (including slashes from the date-based paths). The (?P<filename>.*) regex should handle that, but make sure this URL pattern is placed before any catch-all patterns to avoid conflicts.
For development, add media file serving to your project's urls.py so Django can access uploaded files:
# In your project's urls.py from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # ... your other URLs ... url(r'^downloads/(?P<filename>.*)$', views.downloads, name='downloads') ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
With these changes, when you click the Download link in your DataTable, it should correctly pass the relative file path to your view, which will locate the file in MEDIA_ROOT and trigger the download prompt.
内容的提问来源于stack exchange,提问作者ybrick

