4

I have a simple upload form which includes an image as a FileField:

def post(request):    
    if request.user.is_authenticated():
        form_post = PostForm(request.POST or None, request.FILES or None)
        if form_post.is_valid():
            instance = form_post.save(commit=False)
            instance.user = request.user

            instance.save()

            return HttpResponseRedirect('/home/')
        else:
            form_post = PostForm()

        context = {
            'form_post': form_post,
        }
        return render(request, 'post/post.html', context)
    else:
        return HttpResponseRedirect("/accounts/signup/")

When a user adds an image to the form, it fires this JS function:

$('input#id_image').on('change', function(e) {...} 

which gives a preview of the image. This is the point where I want the image to be uploaded to my media folder directory (I'm using S3 storage). By default, the image is uploaded when the user submits the form, but I want it to be uploaded as soon as $('input#id_image').on('change' is triggered.

What I've done so far is retrieve the image in InMemoryUploadedFile format in my views:

$('input#id_image').on('change', function(e) {
var formData = new FormData();

formData.append('image', $('input[type=file]')[0].files[0]);
formData.append('csrfmiddlewaretoken', $("input[name='csrfmiddlewaretoken']").val());

$.ajax({
    url: '/upload_image/',
    data: formData,
    type: 'POST',
    contentType: false,
    processData: false, 
    ...
});

^ sends to views:

def upload_image(request):
    if request.is_ajax():
        img = request.FILES.get('image')
        print(img) #successfully prints the filename

But I'm stuck in what to do next in terms of uploading this InMemoryUploadedFileto my S3 bucket. Any advice?

Edit

img = request.FILES.get('image')
print(img)  # successfully prints the filename

s3_connection = boto.connect_s3(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, host="us-east-1")
bucket = s3_connection.get_bucket('my-bucket', validate=False)
key = Key(bucket, img.name)
key.send_file(img) #this line fires the error
return HttpResponse('upload ok')

key.send_file(img) returns this error:

socket.gaierror: [Errno 8] nodename nor servname provided, or not known

Traceback (most recent call last):
  File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/zorgan/Desktop/project/site/draft1/views.py", line 201, in upload_image
    key.send_file(img)
  File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/boto/s3/key.py", line 762, in send_file
    chunked_transfer=chunked_transfer, size=size)
  File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/boto/s3/key.py", line 963, in _send_file_internal
    query_args=query_args
  File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/boto/s3/connection.py", line 671, in make_request
    retry_handler=retry_handler
  File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/boto/connection.py", line 1071, in make_request
    retry_handler=retry_handler)
  File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/boto/connection.py", line 1030, in _mexe
    raise ex
  File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/boto/connection.py", line 940, in _mexe
    request.body, request.headers)
  File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/boto/s3/key.py", line 803, in sender
    http_conn.endheaders()
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 1102, in endheaders
    self._send_output(message_body)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 934, in _send_output
    self.send(msg)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 877, in send
    self.connect()
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 1252, in connect
    super().connect()
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 849, in connect
    (self.host,self.port), self.timeout, self.source_address)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/socket.py", line 693, in create_connection
    for res in getaddrinfo(host, port, 0, SOCK_STREAM):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/socket.py", line 732, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno 8] nodename nor servname provided, or not known
Zorgan
  • 6,953
  • 16
  • 88
  • 175

2 Answers2

5

Had trouble getting boto to work but I upgraded to boto3 and it works fine now.

Here's the code:

img = request.FILES.get('image')
session = boto3.Session(
    aws_access_key_id=AWS_ACCESS_KEY_ID,
    aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
)
s3 = session.resource('s3')

s3.Bucket('my-bucket').put_object(Key='media/%s' % img.name, Body=img)
return HttpResponse()

This successfully uploads the image to my bucket during the AJAX call.

Zorgan
  • 6,953
  • 16
  • 88
  • 175
1

Try this,

import boto
from boto.s3.key import Key
from django.http import HttpResponse


def upload_image(request):
    if request.is_ajax():
        img = request.FILES.get('image')
        print(img)  # successfully prints the filename

        s3_connection = boto.connect_s3("YOUR CREDENTIALS")
        bucket = s3_connection.get_bucket('your bucket name')
        key = Key(bucket, img.name)
        key.send_file(img.read())
        return HttpResponse('upload ok')


NB: I didn't tried this, I found one related answer here

JPG
  • 69,639
  • 12
  • 88
  • 162
  • Where can I import `boto` from? – Zorgan Mar 17 '18 at 04:56
  • You can install it via pip command , `pip install boto` see this pip repo -> https://pypi.python.org/pypi/boto – JPG Mar 17 '18 at 09:10
  • @Zorgan I'm slightly modified the answer, please have a look – JPG Mar 17 '18 at 09:33
  • Think I'm getting closer - but I'm getting an `AttributeError: 'bytes' object has no attribute 'tell'` on the last line. Any idea how to fix this? I've added the code and Traceback in my edit. – Zorgan Mar 17 '18 at 10:08
  • try `key.send_file(img)` instead of `key.send_file(img.read())` – JPG Mar 17 '18 at 10:55
  • `key.send_file(img)` returns `socket.gaierror: [Errno 8] nodename nor servname provided, or not known` - i've added the traceback in my edit if you'd like to look. – Zorgan Mar 17 '18 at 11:11
  • I think I'm exhausted :( Please read this [**Amazon S3 Python Client Tutorial**](https://aws.amazon.com/sdk-for-python/) or post a new question regarding your issue – JPG Mar 17 '18 at 11:23
  • Thankyou for the help - and yes I will do that – Zorgan Mar 17 '18 at 11:30
  • If you got right answer, please let me know, that would help to improve my knowledge – JPG Mar 17 '18 at 11:57
  • I couldn't get it working with `boto` but I upgraded to `boto3` and it works fine now. I've posted my answer above. – Zorgan Mar 18 '18 at 04:45
  • 1
    That's appreciated! Thanks for acknowledging me – JPG Mar 18 '18 at 04:49