How to replace csv media file or delete existing media file using kobo v2 API

Hello to everyone. My name is Uche, and I’m a newcomer to the community. I’ve been using ODK for a while now, but I recently decided to switch to Kobotoolbox for a nationwide survey tool I’m working on.
I’m currently having issues replacing a csv media file using the Kobo v2 API. My python script successfully uploads fresh csv media files but fails to upload a file if the name already exists as a media file on the kobo platform. Is it possible to use the Kobo v2 API to replace an existing csv file with a new one with thesame name? and if not can I use the API to delete an existing media file?

Welcome to the community, @uchechinedu01! Could you also share your script so that we could also test and troubleshoot?

Hello @Kal_Lam. Thanks for reaching out. Please find below the python script used to upload a media file. The script successfully uploads a csv file if it does not exist on the kobo server but fails to upload (404 error) if the filename already exists. I want to be able to replace the csv file since the filename is hard-coded on the form.
The script:
import requests, json

KC_URL= “https://kobo.humanitarianresponse.info/api/v2/assets/aRhFBbWKF946rfCsXWA3Yj/files.json

TOKEN = ‘xxxxxxx’
XFORM = ‘aRhFBbWKF946rfCsXWA3Yj’

FILENAME = ‘input_file.csv’
MIME = ‘text/csv’

HEADERS = {‘Authorization’: f’Token {TOKEN}'}
payload = {‘filename’: ‘input_file.csv’}
files = {‘content’: open(‘input_file.csv’, ‘rb’)}
data = {‘description’: ‘Input file’, ‘metadata’: json.dumps(payload), ‘file_type’: ‘form_media’}

res = requests.post(url=KC_URL, headers=HEADERS, data=data, files=files)
print(res)
print(res.request.url)
print(res.request.headers)

1 Like

Hi @uchechinedu01, what you are seeing is the expected behavior of the endpoint. To update the existing CSV, you first need to send a DELETE request for the existing file and then POST the updated one :+1:

1 Like

Hello @Josh I’ve tried sending a DELETE request to remove the existing csv media file, but it throws back a 405 error. Please how can I go about deleting the media file?

Hi @uchechinedu01, can you please share the code you are using to delete the file.

1 Like

Hello @Josh I’ve been able to resolve the issue. I forgot to add a trailing slash to the URL. It is working fine now. The script to replace the media file and redeploy the form now works well. However, the newly uploaded media file is still not reflecting on the form even after redeployment through the API. It only works when I manually redeploy from the dashboard.
Please find below the python script that was used to delete the media file, upload the new file and redeploy the form.

import requests, json

URL = 'https://kobo.humanitarianresponse.info/api/v2/'
TOKEN = ''
XFORM = ''

headers = {'Authorization': f'Token {TOKEN}'}

#### TO DELETE OLD MEDIA FILE

data_url = "%sassets/%s/files/" % (URL, XFORM)

response = requests.get(data_url, headers=headers, params={'format': 'json'})
json_uid = response.json()
media_uid = json_uid['results'][0]['uid']
asset_url = "%s/%s/" % (data_url, media_uid)
res = requests.delete(asset_url, headers=headers)
print(res)
print("Old media file deleted successfully")

#### TO UPLOAD NEW MEDIA FILE

KC_URL= "%sassets/%s/files.json" % (URL, XFORM)

FILENAME = 'input.csv'
MIME = 'text/csv'

payload = {'filename': 'input.csv'}
files = {'content': open('input.csv', 'rb')}
data = {'description': 'Input and equipment media file', 'metadata': json.dumps(payload), 'file_type': 'form_media'}

res = requests.post(url=KC_URL, headers=headers, data=data, files=files)
print(res)
print("New media file uploaded successfully")

#### TO REDEPLOY SECTION 4 FORM

asset_url = "%sassets/%s/" % (URL, XFORM)
headers = {
    'Accept': 'application/json',
    'Authorization': f'Token {TOKEN}'
}

response = requests.get(asset_url, headers=headers, params={'format': 'json'})
print(response.json())
version_to_deploy = response.json()['version_id']
print(version_to_deploy)
files = {
    'version_id': (None, version_to_deploy),
}
response = requests.patch(asset_url + 'deployment/', headers=headers, files=files)
#res = requests.patch(asset_url + 'deployment/', headers=headers, data={'version_id': version_to_deploy})
print(response)
print("Form redeployed successfully")

@uchechinedu01 that’s great! Regarding redeployment, it looks like you’ve left out the active attribute. I’m also not sure why you’re sending the version_id in the files dict — try something like this rather:

deployment_data = {
    'version_id': version_to_deploy,
    'active': True
}
response = requests.patch(asset_url + 'deployment/', headers=headers, data=deployment_data)
1 Like

@Josh Thank you very much, the redeployment section of the script is now working

2 Likes

@uchechinedu01, would you mind sharing the entire scripts (that worked well at your end) so that our community should also benefit from the same?

Okay @Kal_Lam, please find below the developed Python script that does the following

  • Deletes a media file (input.csv)
  • Uploads a new media file (input.csv)
  • Redeploy form to display the newly uploaded media file.

The script:

import requests, json

URL = 'https://<url>/api/v2/'
TOKEN = '<token>'
XFORM = '<form_id>'

headers = {'Authorization': f'Token {TOKEN}'}

#### TO DELETE OLD MEDIA FILE
try:
    data_url = "%sassets/%s/files/" % (URL, XFORM)

    response = requests.get(data_url, headers=headers, params={'format': 'json'})
    json_uid = response.json()
    media_uid = json_uid['results'][0]['uid']
    asset_url = "%s/%s/" % (data_url, media_uid)
    res = requests.delete(asset_url, headers=headers)
    print(res)
    print("Old media file deleted successfully")
except:
    print("No media file uploaded")
    pass
#### TO UPLOAD NEW MEDIA FILE

try:
    KC_URL= "%sassets/%s/files.json" % (URL, XFORM)

    FILENAME = 'input.csv'
    MIME = 'text/csv'

    payload = {'filename': 'input.csv'}
    files = {'content': open('input.csv', 'rb')}
    data = {'description': 'Input and equipment media file', 'metadata': json.dumps(payload), 'file_type': 'form_media'}

    res = requests.post(url=KC_URL, headers=headers, data=data, files=files)
    print(res)
    print("New media file uploaded successfully")
except:
    print("No media file")

#### TO REDEPLOY FORM

asset_url = "%sassets/%s/" % (URL, XFORM)
headers = {
    'Accept': 'application/json',
    'Authorization': f'Token {TOKEN}'
}

response = requests.get(asset_url, headers=headers, params={'format': 'json'})
version_to_deploy = response.json()['version_id']
deployment_data = {
    'version_id': version_to_deploy,
    'active': True
}
response = requests.patch(asset_url + 'deployment/', headers=headers, data=deployment_data)
print(response)
print("Form redeployed successfully")
3 Likes

Thank you, @uchechinedu01, for making the community documentation strong by sharing this python script. Our community should benefit a lot. :clap: :heart: :partying_face:

2 Likes