How do I reference a local media file in a Django template

Viewed 1363

I have set up my media root, media url etc. so the file will show up when I call

http://127.0.0.1:8000/media/something/somewhere/my_pdf.pdf

Now I want to show the same file within a template (i.e. the PDF in an object or embed tag plus some other stuff. I pass the path to the file (i.e. everything after 'media' in the view context, something like:

def test_doc(request):`
    p = r'something/somewhere/my_pdf.pdf'`
    return render(request, 'documents/test.html', {'pdf':p})

So what do I have to put in my template? I tried

<object data="{{ MEDIA_URL }}{{ pdf }}">something</object>

and many many variations thereof. What am I doing wrong?

4 Answers

I tested your approach and I believe I was able to reproduce your issue.

  • PDF was displayed in browser from address: http://127.0.0.1:8000/myapp/media/myapp/my_pdf.pdf
  • PDF not displayed when loaded into an object with <object data="{{ MEDIA_URL }}{{ pdf }}"></object> in template
  • PDF not displayed when loaded into an object with <object data="{% get_media_prefix %}{{ pdf }}"> in template

There are two problems occurring simultaneously.

  1. Django's default project settings enable clickjacking protection using X-Frame-Options. This does not prevent loading the media files with a direct request, but does so when you try to load media into an object. Firefox Inspector shows an error message: The loading of “http://127.0.0.1:8000/myapp/media/myapp/my_pdf.pdf” in a frame is denied by “X-Frame-Options“ directive set to “DENY“.

Django's documentation tells to use @xframe_options_exempt decorator for the view. It did not help in my tests. Disabling clickjacking protection by commenting out 'django.middleware.clickjacking.XFrameOptionsMiddleware' in settings.py allowed me to display PDF in an object with <object data="media/myapp/my_pdf.pdf"> in the template.

  1. Both {{ MEDIA_URL }}{{ pdf }} and {% get_media_prefix %}{{ pdf }} tags in the template lead to loading the PDF from the disk with path "/media/myapp/my_pdf.pdf". Note the extra "/" in the beginning. You can prevent this by defining p = 'media/myapp/my_pdf.pdf' in the view and using <object data="{{ pdf }}"> in the template. Not very elegant, but works when clickjacking middleware is disabled.

Since you have set up MEDIA_ROOT and MEDIA_URL, you should use the {% get_media_prefix %} template tag:

{% load static %}
<object data="{% get_media_prefix %}{{ pdf }}">something</object>

EDIT:

If you are running in development mode (DEBUG = True), you also need to change your urls.py to serve media files:

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    # ...
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

According to your code it doesn't look like MEDIA_URL is defined in your views context.

from django.conf import settings

def test_doc(request):`
    p = r'something/somewhere/my_pdf.pdf'`
    return render(request, 'documents/test.html', {'pdf':p, 'MEDIA_URL': settings.MEDIA_URL})

To complete answer of drec4s that fixes Django side stuff, you will need to add a markup like this one on your template :

<embed type="application/pdf" src= "{% get_media_prefix %}{{ pdf }}" width= "500" height= "375">
Related