Updating a custom field using ASANA Python API

1.5k views Asked by At

I'm trying to update the values of custom fields in my Asana list. I'm using the Official Python client library for the Asana API v1.

My code currently looks like this;

project = "Example Project"
keyword = "Example Task"

print "Logging into ASANA"
api_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
client = asana.Client.basic_auth(api_key)
me = client.users.me()
all_projects = next(workspace for workspace in me['workspaces'])
projects = client.projects.find_by_workspace(all_projects['id'])

for project in projects:
    if 'Example Project' not in project['name']:
        continue
    print "Project found."
    print "\t"+project['name']
    print

    tasks = client.tasks.find_by_project(project['id'], {"opt_fields":"this.name,custom_fields"}, iterator_type=None)

    for task in tasks:
        if keyword in task['name']:
            print "Task found:"
            print "\t"+str(task)
            print
            for custom_field in task['custom_fields']:
                custom_field['text_value'] = "New Data!"
            print client.tasks.update(task['id'], {'data':task})

But when I run the code, the task doesn't update. The return of print client.tasks.update returns all the details of the task, but the custom field has not been updated.

2

There are 2 answers

1
KSmith On

Thanks to Matt, I got to the solution.

new_custom_fields = {}
for custom_field in task['custom_fields']:
  new_custom_fields[custom_field['id']] = "New Data!"

print client.tasks.update(task['id'], {'custom_fields':new_custom_fields})

There were two problems in my original code, the first was that I was trying to treat the API symmetrically and this was identified and solved by Matt. The second was that I was trying to update in an incorrect format. Note the difference between client.tasks.update in my original and updated code.

2
Matt On

I think the problem is that our API is not symmetrical with respect to custom fields... which I kind of find to be a bummer; it can be a real gotcha in cases like this. Rather than being able to set the value of a custom field within the block of values as you're doing above, which is intuitive, you have to set them with a key:value dictionary-like setup of custom_field_id:new_value - not as intuitive, unfortunately. So above, where you have

for custom_field in task['custom_fields']:
  custom_field['text_value'] = "New Data!"

I think you'd have to do something like this:

new_custom_fields = {}
for custom_field in task['custom_fields']:
  new_custom_fields[custom_field['id']] = "New Data!"
task['custom_fields'] = new_custom_fields

The goal is to generate JSON for the POST request that looks something like

{
  "data": {
    "custom_fields":{
      "12345678":"New Data!"
    }
  }
}

As a further note, the value should be the new text string if you have a text custom field, a number if it's a number custom field, and the ID of the enum_options choice (take a look at the third example under this header on our documentation site) if it's an enum custom field.