Creating workflow schemasΒΆ

The API exposes ProjectSchema that can be used to define what ObjectType a project can have together with Status and Type that are valid for the project.

Note

This is an advanced topic, most users will not need it.

Note

ftrack server version 4.5 or higher is required for this example to work.

Below is an example of how to create a complete ProjectSchema

Start by querying the data we need to create our project schema:

status_not_started = session.query('Status where name="{}"'.format('Not started')).one()
status_in_progress = session.query('Status where name="{}"'.format('In progress')).one()
status_completed = session.query('Status where name="{}"'.format('Completed')).one()
status_on_hold = session.query('Status where name="{}"'.format('On Hold')).one()

all_statuses = [status_not_started, status_in_progress, status_completed, status_on_hold]

type_generic = session.query('Type where name="{}"'.format('Generic')).one()
type_modeling = session.query('Type where name="{}"'.format('Modeling')).one()
type_rigging = session.query('Type where name="{}"'.format('Rigging')).one()
type_compositing = session.query('Type where name="{}"'.format('Compositing')).one()
type_deliverable = session.query('Type where name="{}"'.format('Deliverable')).one()
type_character = session.query('Type where name="{}"'.format('Character')).one()

all_types = [type_generic, type_modeling, type_rigging, type_compositing, type_deliverable, type_character]

Create a WorkflowSchema defining statuses tasks can have. Each WorkflowSchema is then linked to one or multiple statuses using a WorkflowSchemaStatus object:

workflow_schema = session.create('WorkflowSchema')

for status in all_statuses:
    session.create('WorkflowSchemaStatus', {
        'workflow_schema_id': workflow_schema['id'],
        'status_id': status['id']
    })

Define task types by creating a TaskTypeSchema, linking it to types through TaskTypeSchemaType:

task_schema = session.create('TaskTypeSchema')

for typ in all_types:
    session.create('TaskTypeSchemaType', {
        'task_type_schema_id': task_schema['id'],
        'type_id': typ['id']
    })

In a similar manner, define which states a version can have by creating another WorkflowSchema:

version_schema =  session.create('WorkflowSchema')

for status in all_statuses:
    session.create('WorkflowSchemaStatus', {
        'workflow_schema_id': version_schema['id'],
        'status_id': status['id']
    })

Then we create the ProjectSchema itself with the ids of the workflows and schemas we already created for Task and AssetVersion:

project_schema = session.create('ProjectSchema', {
    'name': 'My custom schema',
    'task_workflow_schema_id': workflow_schema['id'],
    'task_type_schema_id': task_schema['id'],
    'asset_version_workflow_schema_id': version_schema['id'],
})

Define objects contained in schema, linked with ProjectSchemaObjectType. Also define which statuses and types each object type can have, linked with Schema and SchemaStatus & SchemaType.

In this example we limit Asset Builds to a reduced set of statuses and types.

Milestone is a built in type which will always be part of a ProjectSchema but it also needs to have statuses and types:

objecttype_sequence = session.query('ObjectType where name="{}"'.format('Sequence')).one()
objecttype_shot = session.query('ObjectType where name="{}"'.format('Shot')).one()
objecttype_folder = session.query('ObjectType where name="{}"'.format('Folder')).one()
objecttype_assetbuild = session.query('ObjectType where name="{}"'.format('Asset Build')).one()
objecttype_milestone = session.query('ObjectType where name="{}"'.format('Milestone')).one()

for (objecttype, statuses, types) in [
        (objecttype_sequence, None, None),
        (objecttype_shot, None, None),
        (objecttype_folder, None, None),
        (objecttype_assetbuild,
            [status_in_progress,status_completed,status_on_hold],
            [type_generic, type_character]),
        (objecttype_milestone, None, None),
    ]:
    session.create('ProjectSchemaObjectType', {
        'project_schema_id': project_schema['id'],
        'object_type_id': objecttype['id']
    })

    object_type_schema = session.create('Schema', {
        'project_schema_id': project_schema['id'],
        'object_type_id': objecttype['id']
    })

    for status in statuses or all_statuses:
        session.create('SchemaStatus', {
            'schema_id': object_type_schema['id'],
            'status_id': status['id']
        })
    for typ in types or all_types:
        session.create('SchemaType', {
            'schema_id': object_type_schema['id'],
            'type_id': typ['id']
        })

A more complex ProjectSchema can have overrides for Task where different types of tasks can have different statuses. For example Animation can have different statuses compared to all other types such as Modelling.

Create a override for Deliverable task type, allowing it to only have two states:

override_workflow_schema = session.create('WorkflowSchema', {
    'name': 'My schema deliverable override '
})
for status in [status_in_progress, status_completed]:
    session.create('WorkflowSchemaStatus', {
        'workflow_schema_id': override_workflow_schema['id'],
        'status_id': status['id']
    })

session.create('ProjectSchemaOverride', {
    'project_schema_id': project_schema['id'],
    'type_id': type_deliverable['id'],
    'workflow_schema_id': override_workflow_schema['id'],
})

A task template can be used when creating Asset builds, Shots, etc to also have a predefined set of tasks created. Create a Modeling template containing two task types:

task_template = session.create('TaskTemplate', {
    'project_schema_id': project_schema['id'],
    'name': 'Modeling'
})
for typ in [type_modeling, type_rigging]:
    session.create('TaskTemplateItem', {
        'template_id': task_template['id'],
        'task_type_id': typ['id']
    })

Finally, commit our new project schema:

session.commit()