0

I'm trying to serve an image from a docker volume, but I can't quite get a hang of it.

error message

Page not found (404)
Request Method: GET
Request URL:    http://127.0.0.1:8000/fergana_api/files/36/movies/movie.mp4
Using the URLconf defined in fergana_api.urls, Django tried these URL patterns, in this order:

admin/
api/schema/ [name='api-schema']
api/docs/ [name='api-docs']
api/
[name='all-runs']
tests/<slug:test_session_id> [name='single-run']
tests/<slug:test_session_id>/<slug:test_name> [name='single-test']
^static/(?P<path>.*)$
^files/(?P<path>.*)$
The current path, fergana_api/files/36/movies/movie.mp4, didn’t match any of these.

You’re seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.

settings.py

STATIC_URL = 'static/'
MEDIA_URL = 'files/'

MEDIA_ROOT = '/var/web/media/'
STATIC_ROOT = BASE_DIR / 'static_files'

# location of static files
STATICFILES_DIRS = [
    BASE_DIR / 'static'
]

app/views.py

class SingleTestView(View):
    def get(self, request, test_session_id, test_name):
        run = Runner.objects.get(id=test_session_id)
        path_to_session = to_file('files/', f'{test_session_id}')
        movies_dir_path = to_file(path_to_session, 'movies')
        movie_path = to_file(movies_dir_path, test_name.replace('-', '_') + '.mp4')
        
        context = {
            'movie_path': movie_path
        }

        return render(request, "presenter/single_test.html", context)

project/url.py

if settings.DEBUG:
    urlpatterns += static(
        settings.STATIC_URL, document_root=settings.STATIC_ROOT
                          )

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

single_test.html

<video width="320" height="240" controls>
  <source src="{{ movie_path }}" type="video/mp4">
</video>

It seems like the app uses the correct URL to serve files, but it doesn't seem like it can find/access the MEDIA_ROOT

http://127.0.0.1:8000/fergana_api/files/36/movies/movie.mp4

How do I actually make it serve the file located at /var/web/media/36/movies/movie.mp4 given that the file 100% exists?

  1. Please, tell me if you need any more info
  2. app is included into the INSTALLED_APPS
  3. I'm talking about developer mode only; not asking how to serve files in prod

Added docker-compose

services:
  app:
    build:
      context: .
      dockerfile: fergana-api.dockerfile
      args:
        - DEV=true
    ports:
      - '8000:8000'
    volumes:
      - ./fergana_api:/fergana_api 
      - static-data:/vol/web

volumes:
  static-data:
  • Please include the dockerfile/docker-compose file – Ahmed I. Elsayed May 29 '23 at 13:52
  • `How do I actually make it serve the file` by using django static engine instead of hand-made `"{{ movie_path }}"`. `/var/web/media` this is your MEDIA_ROOT, not STATIC_ROOT. Please take a look at these posts: [one](https://stackoverflow.com/questions/66833381/static-media-images-are-not-displaying-in-django/66834540#66834540) [two](https://stackoverflow.com/questions/75365356/nginx-does-not-seeing-static-files-when-launching-with-docker-compose-gunicorn/75384047#75384047) – Ivan Starostin May 29 '23 at 14:29
  • @IvanStarostin but how do I make it serve files from MEDIA_ROOT? I mean like the answers are focused on STATIC_ROOT, which isn't what I want –  May 30 '23 at 07:43
  • `/var/web` != `/vol/web`. Also moving to docker usually means moving towards _production_ and DEBUG=False. Django is not supposed to serve media files in production, consider using Nginx for this (see one of the links above about mapping django-nginx-docker-compose). – Ivan Starostin May 30 '23 at 17:27

2 Answers2

0

To serve static files in Django + Docker. You need to ensure multiple things

  1. Django serves media files in Development mode, or a server does it in production

  2. A volume is mapped to static between the host and the guest machine. In your case, you need to put something like

Assuming the use of docker-compose (since you'll have a DB server anyway)

# in the api service
volumes
  - media:/vol/path/to/media/in/container


# and the very end
volumes:
  media:

or map it in the Dockerfile if you're not using compose

Ahmed I. Elsayed
  • 2,013
  • 2
  • 17
  • 30
  • @ahmed-i-elsayed I added docker-compose as you suggested. –  May 29 '23 at 13:59
  • @AnatolyRozhkov seems that all is good, your file object is a File instance, not a string instance, to access the underlying URL or path, use file.url or file.path In your template, use file.url instead – Ahmed I. Elsayed May 30 '23 at 08:44
  • I don't get it, where the url part should come from? It's not like I have file in models or anything. –  May 30 '23 at 08:50
  • @AnatolyRozhkov did you try the solution? – Ahmed I. Elsayed May 31 '23 at 17:38
0

Write {{ movie_path.url }} instead of {{ movie_path }} .

<video width="320" height="240" controls>
  <source src="{{ movie_path.url }}" type="video/mp4">
</video>
Darsh Modi
  • 289
  • 1
  • 9
  • what would that do exactly? –  May 30 '23 at 07:39
  • it will give you a full media URL which can be opened in the browser. – Darsh Modi May 30 '23 at 09:35
  • Really, I thought '.' notation is a way to access variables stored in model objects. And I tried you solution and the result was just an empty url –  May 30 '23 at 09:50
  • you have to fix that issue after that you will be able to get that media file on the browser. – Darsh Modi May 30 '23 at 09:51
  • Do you mean I need to somehow save those generated files into models? Do I need to save path to those files? –  May 30 '23 at 10:19
  • yes, file will get stored in file system and path of that file will be stored in DB. – Darsh Modi May 30 '23 at 12:34