Search code examples
djangoamazon-s3vimeodjango-storage

How to store image files in Amazon S3 and Videos in Vimeo using Django


I want to store the image files in the S3 and the video files in the Vimeo in my django project. I am S3Boto3Storage of Django-storage as the storage backend. As Vimeo takes care of compression and content delivery for video files and it's cheap compared to S3, I want to use that for video files.

I thought of uploading the file to the Vimeo using the upload_to attribute in the FileField of django model, but I can't able to get the absolute path of the video file in the method.

here is my implementation of the upload_to method,

import vimeo


def vimeo_client():
    client = vimeo.VimeoClient(
        token=settings.VIMEO_ACCESS_TOKEN,
        key=settings.VIMEO_CLIENT_ID,
        secret=settings.VIMEO_CLIENT_SECRET
    )
    return client

def get_media_path(instance, filename):
    new_filename = '{}.{}'.format(uuid.uuid4(), filename.split('.')[-1])
    if instance.type == 'image':
        file_path = 'posts/media/images/{filename}'.format(
            filename=new_filename)
    else:
        client = vimeo_client()
        file_path = client.upload(
            filename,
            data={
                'name': instance.title,
                'description': instance.description
            }
        )
    logger.info("File uploaded to: [{}]".format(file_path))
    return file_path

But it's giving me this error

OSError: [Errno 2] No such file or directory: 'videoplayback.mp4'

Or I could customise the S3Boto3Storage for my purpose. I would like to know what would be the better solution.

Edit Here is the full stack trace

Traceback (most recent call last):
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 157, in __call__
response = self.get_response(request)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/core/handlers/base.py", line 124, in get_response
response = self._middleware_chain(request)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/core/handlers/exception.py", line 43, in inner
response = response_for_exception(request, exc)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception
response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/core/handlers/exception.py", line 139, in handle_uncaught_exception
return debug.technical_500_response(request, *exc_info)
File "/Users/rohanroy/development/django/zappa/appcore/src/appcore/wsgi.py", line 24, in null_technical_500_response
six.reraise(exc_type, exc_value, tb)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/core/handlers/base.py", line 249, in _legacy_get_response
response = self._get_response(request)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/contrib/admin/options.py", line 551, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/utils/decorators.py", line 149, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/views/decorators/cache.py", line 57, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/contrib/admin/sites.py", line 224, in inner
return view(request, *args, **kwargs)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/contrib/admin/options.py", line 1508, in add_view
return self.changeform_view(request, None, form_url, extra_context)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/utils/decorators.py", line 67, in _wrapper
return bound_func(*args, **kwargs)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/utils/decorators.py", line 149, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/utils/decorators.py", line 63, in bound_func
return func.__get__(self, type(self))(*args2, **kwargs2)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/contrib/admin/options.py", line 1408, in changeform_view
return self._changeform_view(request, object_id, form_url, extra_context)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/contrib/admin/options.py", line 1448, in _changeform_view
self.save_model(request, new_object, form, not add)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/contrib/admin/options.py", line 979, in save_model
obj.save()
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/db/models/base.py", line 808, in save
force_update=force_update, update_fields=update_fields)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/db/models/base.py", line 838, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/db/models/base.py", line 924, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/db/models/base.py", line 963, in _do_insert
using=using, raw=raw)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/db/models/query.py", line 1076, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 1112, in execute_sql
for sql, params in self.as_sql():
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 1065, in as_sql
for obj in self.query.objs
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 1014, in pre_save_val
return field.pre_save(obj, add=True)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/db/models/fields/files.py", line 296, in pre_save
file.save(file.name, file.file, save=False)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/db/models/fields/files.py", line 93, in save
name = self.field.generate_filename(self.instance, name)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/django/db/models/fields/files.py", line 327, in generate_filename
filename = self.upload_to(instance, filename)
File "/Users/rohanroy/development/django/zappa/appcore/src/utils/common.py", line 50, in get_media_path
'description': instance.description
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/vimeo/upload.py", line 49, in upload
filesize = self.__get_file_size(filename)
File "/Users/rohanroy/development/django/zappa/arete/lib/python2.7/site-packages/vimeo/upload.py", line 163, in __get_file_size
return os.path.getsize(filename)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/genericpath.py", line 57, in getsize
return os.stat(filename).st_size
OSError: [Errno 2] No such file or directory: 'videoplayback.mp4'

Solution

  • Vimeo API's supports 3 types of video upload strategies which are discussed here. The tus approach assumes that the video file is in the local system. To upload video from the browser one need to use the form-based uploads approach which is not useful for an API only server. There is two option to tackle this,

    1. Upload the video from the client-side to the API server using your own API endpoint and then use vimeo.py to upload it to the Vimeo and delete the actual video file from the server.

    2. Use vimeo.js to upload the video file from the client side and then store the returned video_uri in the backend.