Search code examples
pythonrestpython-requestsprestashop

Python Requests PUT to update image in Prestashop


I'm trying to update an existing image from a product in prestashop. I'm using Python and Requests and the following code:

import requests
import io
import mimetypes
from PIL import Image
from StringIO import StringIO

api_key = 'test'

url = "https://.../api/images/products/249/445"

file_name = 't3_6kxvzv.jpg'
fd = io.open(file_name, "rb")
content = fd.read()
fd.close()

def encode_multipart_formdata():
    """Encode files to an http multipart/form-data.
    :param files: a sequence of (type, filename, value)
        elements for data to be uploaded as files.
    :return: headers and body.
    """
    BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'
    CRLF = '\r\n'
    L = []
    L.append('--' + BOUNDARY)
    L.append(
        'Content-Disposition: form-data; \
            name="%s"; filename="%s"' % ("image", file_name))
    L.append('Content-Type: %s' % get_content_type(file_name))
    L.append('')
    L.append(content)
    L.append('--' + BOUNDARY + '--')
    L.append('')
    body = CRLF.join(L)
    headers = {
         'Content-Type': 'multipart/form-data; boundary=%s' % BOUNDARY
    }
    return headers, body

def get_content_type(file_name):
    """Retrieve filename mimetype.
    :param filename: file name.
    :return: mimetype.
    """
    return mimetypes.guess_type(file_name)[0] or 'application/octet- stream'

header, body = encode_multipart_formdata()

r = requests.put(url, data=body, auth=(api_key,""), headers= header)
# also tried data = content

r = requests.get(url, auth=(api_key,""))
i = Image.open(StringIO(r.content))
i.show()

I tried various PUT and POST requests with

data = content 

but getting only a 400 status code.

I then tried to GET the existing image, which works fine.

The api_key has all the necessary setting to allow PUT and POST.

I then tried to read into how prestapyt is solving this problem, however after importing prestapyt I couldn't follow their documentation to add an image to a product using:

prestashop.add("https://...api/images/products/249/445", files[('image',file_name,content)])

produces:

KeyError: ('image', 't3_6kxvzv.jpg', '\xff\xd8\xff\xe0\x00\x10JFI...

I tried then to modify the encode_multipart_formdata and get_content_type functions to produce a similar solution, but cannot get past the 400 status code.

I would very much prefer to use Requests and try to understand how to update a picture to using prestapyt and a turn-key solution.

Thank you for your time!

Documentation I used: Prestashop http://doc.prestashop.com/display/PS16/Chapter+9+-+Image+management

prestapyt https://github.com/prestapyt/prestapyt

UPDATE:

I was able to use Requests and POST to add an image to a product via:

url_2 = "https:/.../api/images/products/249"
r = requests.post(url_2, data=body, auth=(api_key,""), headers=header)

Still not able to use PUT to change or update an image.


Solution

  • This answer comes a little bit late, but here it is. You're reinventing the wheel, altough it's being interesting seeing how: now I understand how to build a multipart form data from scratch. I tried your code and it fails since youre joining str and bytes in your encode_multipart_formdata function:

    L.append(content)
    

    That line will raise a TypeError exception.

    Requests can post multipart form data in a very simple way:

    files = {'image': ('../imagepath/imagename.jpg', open('../imagepath/imagename.jpg', 'rb'), 'image/jpg')}
    body, content_type = requests.models.RequestEncodingMixin._encode_files(files, {})
    
    headers = {
        "Content-Type": content_type
    }
    
    r=requests.post(  url + "images/products/" + str(product_id),data=body, headers=headers)
    
    print(r.text)
    

    This has been tested with Python 3.7 and PrestaShop 1.7.8.2.