Handling media files for Django in production on Render

Hi,
Thank you for your availability and for the Render cloud services.

I rode the docs, and i think all the topics related to “the Django media files” from the community. Sorry if my make you repeat. I hope it won’t be too long, and my english enough correct.
I’m aware that i do not use a persistent storage.
I try to describe as well as i can the problem. As far as i understand a persistent storage is not mandatory to have a working Django on Render. At each deploy, or service start, all the datas are lost, it’s ok for me right now.
My dummy Django app initialization consists of creating dummy datas ready to use: static and media files.

A beginner question, thanks for your understanding.
Locally i deploy the application with a docker compose file where Nginx is the reverse proxy serving static and media files. No problems.
Using Render in a DEBUG mode to True, Django manage to serve the files (so they all exists, in the expected folders set).
Using Render in a DEBUG mode to False, my static files are rendered, but not the media ones.

[usecase]
Django is host as a free web service.
Basic settings, no CORS set.
DEBUG = False.
MEDIA_URL = “/media/”
MEDIA_ROOT = os.path.join(BASE_DIR, ‘media’)

[about the render instance]
All my media files are copied into the project root “media”. ACLS ok, and all belong to user render.

[from the browser console network tab]
I can see the GET requests to my media files. Example below:

initiator: image
type: html
status code: 200
content-type: text/html; charset=utf-8

[MIME type] i can see initiator “image” because my images are in a tag. But it seems the GET request does not return an image, it returns HTML (which i can not read from console).

[Detailed stack trace] i managed to access more details of there error. It’s seems to be the relevant observation which explains the MIME type mismatch. Below is the trace. The problem seems indeed to be related to how Django and Render handle media file requests.
I do not understand what’s going on. As a beginner perspective, requesting a file from templates folder or media folder is processed the same way (a GET request). I do not understand why Render should find files in a “templates” folder and not those from “media” folder (they could have be called differently). For the static files i suppose it has something related to the fact that static resources are handled by whitenoise.
As i said, i tried to debug before asking you (and i took times trying to be sure i not have a dummy mistake somewhere).

[problem in brief]
Instead of serve a file from Render, Django tries to resolve a route named “/media/*”

File “/opt/render/project/src/venv/lib/python3.11/site-packages/django/core/handlers/exception.py”, line 55, in inner
response = get_response(request)
^^^^^^^^^^^^^^^^^^^^^
File “/opt/render/project/src/venv/lib/python3.11/site-packages/django/core/handlers/base.py”, line 181, in _get_response
callback, callback_args, callback_kwargs = self.resolve_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/opt/render/project/src/venv/lib/python3.11/site-packages/django/core/handlers/base.py”, line 313, in resolve_request
resolver_match = resolver.resolve(request.path_info)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/opt/render/project/src/venv/lib/python3.11/site-packages/django/urls/resolvers.py”, line 705, in resolve
** raise Resolver404({“tried”: tried, “path”: new_path})**
django.urls.exceptions.Resolver404: {‘tried’: [[<URLResolver (admin:admin) ‘admin/’>], [<URLPattern ‘’ [name=‘home’]>], [<URLPattern ‘home/’ [name=‘home’]>], [<URLPattern ‘photos/’ [name=‘photos’]>], [<URLPattern ‘photos/add/’ [name=‘photos_add’]>], [<URLPattern ‘photos/add-multiple/’ [name=‘photos_add_multiple’]>], [<URLPattern ‘photos/int:id/detail/’ [name=‘photos_detail’]>], [<URLPattern ‘photos/int:id/update/’ [name=‘photos_update’]>], [<URLPattern ‘photos/int:id/delete/’ [name=‘photos_delete’]>], [<URLPattern ‘posts/’ [name=‘posts’]>], [<URLPattern ‘posts/add/’ [name=‘posts_add’]>], [<URLPattern ‘posts/int:id/detail/’ [name=‘posts_detail’]>], [<URLPattern ‘posts/int:id/update/’ [name=‘posts_update’]>], [<URLPattern ‘posts/int:id/delete/’ [name=‘posts_delete’]>], [<URLPattern ‘users/follow/’ [name=‘follow_user’]>], [<URLPattern ‘feed/’ [name=‘feed’]>], [<URLPattern ‘contact_admin/’ [name=‘contact_admin’]>], [<URLPattern ‘signin/’ [name=‘signin’]>], [<URLPattern ‘profile/update/’ [name=‘update_profile_image’]>], [<URLPattern ‘login/’ [name=‘login’]>], [<URLPattern ‘logout/’ [name=‘logout’]>], [<URLPattern ‘password-change/’ [name=‘password_change’]>], [<URLPattern ‘password-change/done/’ [name=‘password_change_done’]>], [<URLPattern ‘password_reset/’ [name=‘password_reset’]>], [<URLPattern ‘password_reset/done/’ [name=‘password_reset_done’]>], [<URLPattern ‘reset///’ [name=‘password_reset_confirm’]>], [<URLPattern ‘reset/done/’ [name=‘password_reset_complete’]>]], ‘path’: ‘media/billet_1.jpg’}

[the question]
I prefered to describe as much as i can. I’m looking for information about how Render handles the Django media files.
I saw people fixing such a problem by adding a route to urls.py, dedicated to “media”, but doing so they use Django, not a reverse proxy. So i do not want to do it.

Thanks a lot.

Hey there,
Sorry for super long message. I should have take time to think about the “problem” after long readings.
Beginner problem sorry.
The explanation:

  • as soon as Django DEBUG setting is False, and without using an external storage for media files, Django will not serve anything. It expects a web server or a mechasnism to serve the static and media files
  • statics files are “rendered” because they are handled by whitenoise

So it’s mandatory to use an external storage (or “such a mechanism”) as soon as we need to run Django in production fo rmedia files, it’s not an option. However it’s possible to force Django to serve files when Debug is False, but it’s not recommended for performance.
As i did not know this basic consideration, i did not understand why i should use the external storage as the Render docs indicates.
So problem is closed :slight_smile:

Thanks for sharing what you learned! Closing this one out.

Regards,
Mike


Render Support Engineer, MT (UTC-6, UTC-7 in Winter)

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.