Skip to main content

Managing custom attributes

info

The code examples in this article is only documented with the Python API Client. While many concepts still apply for the JavaScript API, implementation details might differ.

From the API it is not only possible to read and update custom attributes for entities, but also managing custom attribute configurations.

Existing custom attribute configurations can be queried as:

# Print all existing custom attribute configurations.
print(session.query('CustomAttributeConfiguration').all())

Use Session.create to create a new custom attribute configuration:

# Get the custom attribute type.
custom_attribute_type = session.query(
'CustomAttributeType where name is "text"'
).one()

# Create a custom attribute configuration.
session.create('CustomAttributeConfiguration', {
'entity_type': 'assetversion',
'type': custom_attribute_type,
'label': 'Asset version text attribute',
'key': 'asset_version_text_attribute',
'default': 'bar',
'config': json.dumps({'markdown': False})
})

# Persist it to the ftrack instance.
session.commit()
tip

The example above does not add security roles. This can be done either from System Settings in the ftrack web application, or by following the example/manage_custom_attribute_configuration/security_roles example.

Global or project specific

A custom attribute can be global or project specific depending on the [project_id] attribute:

# Create a custom attribute configuration.
session.create('CustomAttributeConfiguration', {
# Set the `project_id` and the custom attribute will only be available
# on `my_project`.
'project_id': my_project['id'],
'entity_type': 'assetversion',
'type': custom_attribute_type,
'label': 'Asset version text attribute',
'key': 'asset_version_text_attribute',
'default': 'bar',
'config': json.dumps({'markdown': False})
})
session.commit()

A project specific custom attribute can be changed to a global:

custom_attribute_configuration['project_id'] = None
session.commit()

Changing a global custom attribute configuration to a project specific is not allowed.

Entity types

Custom attribute configuration entity types are using a legacy notation. A configuration can have one of the following as entity_type:

TypedContext (task)

Represents TypedContext (Folder, Shot, Sequence, Task, etc.) custom attribute configurations. When setting this as entity_type the object_type_id must be set as well.

Creating a text custom attribute for Folder:

custom_attribute_type = session.query(
'CustomAttributeType where name is "text"'
).one()
object_type = session.query('ObjectType where name is "Folder"').one()
session.create('CustomAttributeConfiguration', {
'entity_type': 'task',
'object_type_id': object_type['id'],
'type': custom_attribute_type,
'label': 'Foo',
'key': 'foo',
'default': 'bar',
'config': json.dumps({'markdown': False})
})
session.commit()

Can be associated with a project_id.

Project (show)

Represents Projects custom attribute configurations.

Can be associated with a project_id.

AssetVersion (assetversion)

Represents AssetVersion custom attribute configurations. Can be associated with a project_id.

User (user)

Represents User custom attribute configurations. Must be global and cannot be associated with a project_id.

List (list)

Represents List custom attribute configurations. Can be associated with a project_id.

Asset (asset)

Represents Asset custom attribute configurations.

note

Asset custom attributes have limited support in the ftrack web interface.

Can be associated with a project_id.

It is not possible to change type after a custom attribute configuration has been created.

Custom attribute configuration types

Custom attributes can be of different data types depending on what type is set in the configuration. Some types requires an extra json encoded config to be set:

text

A sting type custom attribute.

The default value must be either str or unicode.

Can be either presented as raw text or markdown formatted in applicaitons which support it. This is configured through a markwdown key:

# Get the custom attribute type.
custom_attribute_type = session.query(
'CustomAttributeType where name is "text"'
).one()

# Create a custom attribute configuration.
session.create('CustomAttributeConfiguration', {
'entity_type': 'assetversion',
'type': custom_attribute_type,
'label': 'Asset version text attribute',
'key': 'asset_version_text_attribute',
'default': 'bar',
'config': json.dumps({'markdown': False})
})

# Persist it to the ftrack instance.
session.commit()

boolean

A boolean type custom attribute. The default value must be a bool. No config is required.

date

A date type custom attribute. The default value must be an arrow date - e.g. arrow.Arrow(2017, 2, 8). No config is required.

enumerator

An enumerator type custom attribute. The default value must be a list with either str or unicode. The enumerator can either be single or multi select. The config must a json dump of a dictionary containing [multiSelect] and [data]. Where [multiSelect] is True or False and data is a list of options. Each option should be a dictionary containing [value] and [menu], where [menu] is meant to be used as label in a user interface.

Create a custom attribute enumerator:

custom_attribute_type = session.query(
'CustomAttributeType where name is "enumerator"'
).first()
session.create('CustomAttributeConfiguration', {
'entity_type': 'assetversion',
'type': custom_attribute_type,
'label': 'Enumerator attribute',
'key': 'enumerator_attribute',
'default': ['bar'],
'config': json.dumps({
'multiSelect': True,
'data': json.dumps([
{'menu': 'Foo', 'value': 'foo'},
{'menu': 'Bar', 'value': 'bar'}
])
})
})
session.commit()

dynamic enumerator

An enumerator type where available options are fetched from remote. Created in the same way as enumerator but without data.

number

A number custom attribute can be either decimal or integer for presentation.

This can be configured through the isdecimal config option:

custom_attribute_type = session.query(
'CustomAttributeType where name is "number"'
).first()
session.create('CustomAttributeConfiguration', {
'entity_type': 'assetversion',
'type': custom_attribute_type,
'label': 'Number attribute',
'key': 'number_attribute',
'default': 42,
'config': json.dumps({
'isdecimal': True
})
})
session.commit()
info

A link between entities in ftrack can be created as a custom attribute using the CustomAttributeLinkConfiguration schema. Links are different from regular custom attributes and they can be used differently in queries. Read more about how to use them here.

Links do not have a type or default value like regular CustomAttributeConfiguration objects, instead they have the following attributes:

  • one_to_one: Boolean used to specify if the link can represent multiple relations or just a single relation.
  • entity_type_to: Represents the entity this link can point to. Valid values are show, task, asset_version, list, user, group, asset and component.
  • object_type_id_to: When setting entity_type_to to "task" object_type_id_to must also be specified.

Below is an example of how to create a custom attribute link between a TypedContext object such as Shot and AssetVersion::

security_role = session.query('SecurityRole').first()

task_object_id = session.query('ObjectType where name is "task"').one()['id']

session.create(
'CustomAttributeLinkConfiguration',
{
'entity_type': 'task',
'object_type_id': task_object_id,
'entity_type_to': 'asset_version',
'label': 'Delivered version',
'key': 'delivered_version',
'config': '{}',
'one_to_one': True,
'write_security_roles': [security_role],
'read_security_roles': [security_role]
}
)

An other example creating a custom attribute link between a Sequence and a Shot specifying object_type for both sides.

security_role = session.query('SecurityRole').first()

shot_object_id = session.query('ObjectType where name is "shot"').one()['id']

sequence_object_id = session.query('ObjectType where name is "sequence"').one()['id']

session.create(
'CustomAttributeLinkConfiguration',
{
'entity_type': 'task',
'object_type_id': sequence_object_id,
'entity_type_to': 'task',
'object_type_id_to': shot_object_id,
'label': 'Master shot',
'key': 'master_shot',
'config': '{}',
'one_to_one': True,
'write_security_roles': [security_role],
'read_security_roles': [security_role]
}
)

Changing default

It is possible to update the [default] value of a custom attribute configuration. This will not change the value of any existing custom attributes:

# Change the default value of custom attributes. This will only affect
# newly created entities.
custom_attribute_configuration['default'] = 43
session.commit()

Security roles

By default new custom attribute configurations and the entity values are not readable or writable by any security role.

This can be configured through the [read_security_roles] and [write_security_roles] attributes:

# Pick random security role.
security_role = session.query('SecurityRole').first()
custom_attribute_type = session.query(
'CustomAttributeType where name is "date"'
).first()
session.create('CustomAttributeConfiguration', {
'entity_type': 'assetversion',
'type': custom_attribute_type,
'label': 'Date attribute',
'key': 'date_attribute',
'default': arrow.Arrow(2017, 2, 8),
'write_security_roles': [security_role],
'read_security_roles': [security_role]
})
session.commit()
note

Setting the correct security role is important and must be changed to whatever security role is appropriate for your configuration and intended purpose.

Custom attribute groups

A custom attribute configuration can be categorized using a CustomAttributeGroup:

group = session.query('CustomAttributeGroup').first()
security_role = session.query('SecurityRole').first()
custom_attribute_type = session.query(
'CustomAttributeType where name is "enumerator"'
).first()
session.create('CustomAttributeConfiguration', {
'entity_type': 'assetversion',
'type': custom_attribute_type,
'label': 'Enumerator attribute',
'key': 'enumerator_attribute',
'default': ['bar'],
'config': json.dumps({
'multiSelect': True,
'data': json.dumps([
{'menu': 'Foo', 'value': 'foo'},
{'menu': 'Bar', 'value': 'bar'}
])
}),
'group': group,
'write_security_roles': [security_role],
'read_security_roles': [security_role]
})
session.commit()
tip

Read also the article about how to use Custom attributes