Search code examples
python-3.xdrupal

Using Python to upload an image to Drupal


Via the JSON:API I'm creating and updating content entities on Drupal 9.5.8 - for content, taxonomies, relationships it's working fine.

But I can't get images to upload - they seem to be corrupted. I've tried this sort of script: https://www.drupal.org/project/drupal/issues/3079384#comment-13250753

import requests
import os

from requests.auth import HTTPBasicAuth


def upload_image(image_path):
    api_url = 'https://example.com/jsonapi/node/event/a8ef729b-1fd6-4233-979a-fa0f81132dde/field_image' #?_format=json
    auth = HTTPBasicAuth('Username', 'Password')
    image_filename = os.path.basename(image_path)
    headers = {'Content-Type': 'application/octet-stream',
    'Content-Disposition': 'file; filename="{}"'.format(image_filename.replace('images/', ''))}
    multipart_form_data = {'file': (image_filename, open(image_path, 'rb'))}

    print(api_url)
    print(auth)
    print(image_filename)
    print(headers)
    
    response = requests.post(api_url, files=multipart_form_data, headers=headers, auth=auth)
    
    print(response.json())
    return None
    

upload_image('images/test.jpg')

And I've tried and errored with a few other / similar approaches like:

def upload_image2(image_path):
    api_url = 'https://example.com/jsonapi/node/event/a8ef729b-1fd6-4233-979a-fa0f81132dde/field_image' #?_format=json
    auth = HTTPBasicAuth('Username', 'Password')
    image_filename = os.path.basename(image_path)
    headers = {'Accept': 'application/vnd.api+json',
            'Content-Type': 'application/octet-stream',
            'Content-Disposition': f'file; filename="{image_filename}"'
        }
    with open('images/test.jpg', 'rb') as f:
        response = requests.post(api_url, headers=headers, auth=auth, files={'test.jpg': f})
        
        print(response.json())

    return None

Strange enough: Adding #?_format=json to the upload_image2 doesn't change anything. But adding it to upload_image, I receive an error:

{'message': 'No route found for the specified format json. Supported formats: api_json.'}

The image that I'm uploading is 11.1 kB (just trying to upload this screenshot) enter image description here

What I see on the website / edit form seems to be broken: enter image description here

The uploaded image is 11.3 kB - which I can't upload here, since it's a broken image, as it seems.

According to that comment, I'm not trying to base64 encode the image.

There is a CURL and Node.js example - but I wasn't able to transfer it to Python, as it seems.

And in this ticket, it seems as if BasicAuth can be used as well to upload files, so that might not be the issue as well.

What am I doing wrong?


Solution

  • After much fiddling around, I was able to get it working via this Code: https://www.drupal.org/node/3024331#comment-13248319

    It seems like

    data = bytearray(data)
    

    was the missing piece.