Actions and API
This page documents the relationship action API, the public routes registered by
the extension, and its package_show integration.
Core actions
relationship_relation_create
Creates a relationship.
Parameters:
| Key | Required | Notes |
|---|---|---|
subject_id |
yes | Use the CKAN ID. For direct action calls, name + name is allowed only when ckanext.relationship.allow_name_based_relation_create = true |
object_id |
yes | Use the CKAN ID. For direct action calls, name + name is allowed only when ckanext.relationship.allow_name_based_relation_create = true |
relation_type |
yes | One of the configured relationship types. Built-ins are related_to, child_of, and parent_of |
extras |
no | Extra metadata stored with the relationship |
Behavior:
- Duplicate relationships are ignored.
- The reverse relationship is created automatically.
- Mixed identifier pairs such as
id + nameare rejected. - This direct action stores the accepted identifiers as provided; it does not try
to resolve
name + nameintoid + id.
Example:
tk.get_action("relationship_relation_create")(
{"user": "alice"},
{
"subject_id": package_a_id,
"object_id": package_b_id,
"relation_type": "related_to",
"extras": {"source": "manual-link"},
},
)
relationship_relation_delete
Deletes a relationship.
Parameters:
| Key | Required | Notes |
|---|---|---|
subject_id |
yes | CKAN ID or entity name |
object_id |
yes | CKAN ID or entity name |
relation_type |
no | If omitted, all matching rows between the two entities are removed |
Behavior:
- Removes the relationship in both directions.
relationship_relations_list
Returns matching relationship rows for a subject.
Parameters:
| Key | Required | Notes |
|---|---|---|
subject_id |
yes | Use the subject entity ID. Name lookups are supported only for some legacy rows |
object_entity |
no | package, organization, or group |
object_type |
no | Related entity type |
relation_type |
no | One of the configured relationship types |
relationship_relations_ids_list
Same filter contract as relationship_relations_list, but returns a unique list
of object_id values.
Identifier behavior
For predictable results, use CKAN IDs in all relationship actions.
The implementation also supports some name-based behavior for backward compatibility:
relationship_relation_createacceptsname + nameonly whenckanext.relationship.allow_name_based_relation_create = true- direct
relationship_relation_createdoes not normalize accepted names to IDs relationship_relation_deletecan remove rows addressed by ID or by namerelationship_relations_listandrelationship_relations_ids_listare asymmetric: an ID lookup can find rows created by name, but a name lookup does not reliably find rows created by ID- scheming-backed dataset create and update flows resolve related names to local IDs when possible
- if scheming-backed create or update cannot resolve both sides and
ckanext.relationship.allow_name_based_relation_create = true, it can store a temporaryname + namerow - the same scheming flow can later rewrite that temporary or legacy
name + name,id + name, orname + idrow to canonicalid + idonce both local entities exist
Extending relationship types
Other extensions can register additional relationship types by implementing
ckanext.relationship.interfaces.IRelationship and returning a mapping of
relation_type -> reverse_relation_type.
For example:
import ckan.plugins as p
from ckanext.relationship.interfaces import IRelationship
class CustomRelationshipPlugin(p.SingletonPlugin):
p.implements(IRelationship)
def get_relationship_types(self):
return {
"depends_on": "required_by",
"required_by": "depends_on",
"references": "references",
}
def get_relationship_type_metadata(self):
return {
"depends_on": {"label": "Depends on", "color": "#7b61ff"},
"required_by": {"label": "Required by", "color": "#f08c2e"},
"references": {"label": "References", "color": "#2a9d8f"},
}
relationship_get_entity_list
Returns entities of a given kind and type.
Parameters:
| Key | Required |
|---|---|
entity |
yes |
entity_type |
yes |
Return shape:
- list of
(id, name, title)tuples
relationship_autocomplete
Package-only autocomplete backend used by the autocomplete form snippet.
Parameters:
| Key | Required |
|---|---|
current_entity_id |
yes |
entity |
no, defaults to package; only package is supported |
entity_type |
yes |
incomplete |
no |
updatable_only |
no |
owned_only |
no |
check_sysadmin |
no |
format_autocomplete_helper |
no |
Return shape:
- JSON payload formatted by
relationship_format_autocompleteor a custom helper
See Package autocomplete for field-level usage.
Optional graph plugin
The graph action API and graph endpoint are registered only when the optional
relationship_graph plugin is enabled.
relationship_graph
Returns a graph-shaped JSON payload for the requested center object.
Parameters:
| Key | Required | Notes |
|---|---|---|
object_id |
yes | CKAN ID or legacy name of the graph center |
object_entity |
no | package, organization, or group. Defaults to package |
object_type |
no | Defaults to dataset |
depth |
no | Breadth-first traversal depth, 1..4 |
relation_types |
no | Filter list of relation types |
max_nodes |
no | Node cap, 1..300, defaults to 100 |
include_unresolved |
no | Include unresolved legacy name-based nodes |
include_reverse |
no | Traverse rows where the current node appears as object_id |
with_titles |
no | Include human-readable titles when available |
Return shape:
{
"nodes": [],
"edges": [],
"meta": {
"depth": 2,
"max_nodes": 100,
"truncated": false
}
}
Notes:
- The traversal is breadth-first.
- Cycles are deduplicated with a visited set.
- Legacy rows stored by
nameare supported. - If the center object is missing, the action raises
NotFound. - If the current user cannot read the center object, the action raises
NotAuthorized.
Public routes
/api/2/util/relationships/autocomplete
Purpose:
- Frontend endpoint for the package autocomplete widget.
- Useful for custom frontends that want the same search behavior.
entity=packageis the only supported mode.
/api/2/util/relationships/graph
Purpose:
- Frontend endpoint for the relationship graph snippet from the optional
relationship_graphplugin. - Returns the
relationship_graphpayload as JSON.
Query parameters:
| Parameter | Required |
|---|---|
object_id |
yes |
object_entity |
no |
object_type |
no |
depth |
no |
relation_types |
no |
max_nodes |
no |
include_unresolved |
no |
include_reverse |
no |
with_titles |
no |
Notes:
- Returns
404when the center object cannot be resolved. - Returns
403when the current user cannot read the center object.
/relationship/section
Purpose:
- Fragment endpoint for lazy-loading related packages with the shipped template snippets.
Query parameters:
| Parameter | Required |
|---|---|
pkg_id |
yes |
object_type |
yes |
relation_type |
yes |
start |
no |
size |
no |
Notes:
- This route is package-only.
- The default batch size is
20.
package_show chaining
Relationship-backed fields can be included in package_show output as lists of
related entity IDs.
Example:
package = tk.get_action("package_show")(
{"ignore_auth": True},
{"id": package_id, "with_relationships": True},
)
related_ids = package["related_packages"]
Default hiding on search and read
By default, relationship fields are omitted from package_show output on:
searchread
You can:
- Change that globally with
ckanext.relationship.views_without_relationships_in_package_show. - Force inclusion for a specific request by passing
with_relationships=True.