0

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.

KSmith
  • 3
  • 3

2 Answers2

1

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.

Matt
  • 10,434
  • 1
  • 36
  • 45
  • The result of client.tasks.update(task['id'], {'data':task}) appears to return the original task. – KSmith Dec 22 '16 at 08:16
  • Perhaps there has been some update to the API, I am passing a Json that looks like this: {'data': {'custom_fields': {'1203012693580045': '1203012693586629'}}} I also tried with the cooresponding name for the option: {'data': {'custom_fields': {'1203012693580045': '1 Month or ++'}}} Both return: "ValueError: dictionary update sequence element #0 has length 1; 2 is required" From that I get that the "data" element should also have some other pointer in the parameter sent. Any one knows? – Carlo A. Fernandez B. Sep 21 '22 at 07:32
0

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.

KSmith
  • 3
  • 3
  • Perhaps there has been some update to the API, I am passing a Json that looks like this: {'data': {'custom_fields': {'1203012693580045': '1203012693586629'}}} I also tried with the cooresponding name for the option: {'data': {'custom_fields': {'1203012693580045': '1 Month or ++'}}} Both return: "ValueError: dictionary update sequence element #0 has length 1; 2 is required" From that I get that the "data" element should also have some other pointer in the parameter sent. Any one knows? – Carlo A. Fernandez B. Sep 21 '22 at 07:30