Since SQL is a relational database, Directus has several UIs that can help clearly and easily manage relationships between items. An item can have related items from the same table (eg: Project -> Related Project) or a different table (eg: Project -> Category). An item can also have relationships to a single item (eg: Shirt -> Size) in a Many-to-One (or One-to-Many) relationship, or to multiple items (eg Shirt -> Materials) through Many-to-Many relationships.
Many-to-One relationships save the id
from another item as it's value, creating a dynamic relationship to that item.
Many-to-Many relationships are quite a bit more complex, but very powerful. There are two things that are important to understand for M2Ms: Junction Tables, and Aliases. Let's use our Shirt -> Materials example from before to explore how this works:
shirt (Table)
* id
* name
* size
* "materials" (M2M Alias)
materials (Table)
* id
* material
shirt_materials (Junction Table)
* id
* shirt_id
* material_id
We can't efficiently store multiple values in a single field, so M2M fields store all their relationships in a separate table called a "junction table" created just for this purpose. Junction tables are very simple – like all Directus tables they have an id
column, but they also have two more columns for storing the IDs of the two items it's relating. In this case we're linking a shirts with their respective materials – so we have a shirt_materials
junction table with shirt_id
and material_id
columns.
Another thing you may have noticed is that the materials
column says Alias
and has quotes around it. Since we're not actually storing anything in that column (remember, values are stored in the Junction Table) we don't need to create it in the database. Instead, Directus uses an Alias column (like a ghost column) to represent a column for M2M UIs. Aliases columns don't exist in your database schema, they are added directly into the directus_columns
table (a good place to look for bulk creation or troubleshooting).
Since relational UIs can get slightly complex, if you can't get one working or run into issues check out our Troubleshooting Relationships section.
Supported Datatypes: INT
This is a M2O relational UI that links a single file (and YouTube/Vimeo video embeds) by storing the related item's ID – which is why this UI only works with the INT datatype (also used for IDs). If you have a books
table you could use this for the cover_image
column, for a projects
table this would be the UI used for columns like: thumbnail_image
, wireframe_pdf
, and background_video
. Basically any column that needs to store a single file.
allowed_filetypes
: A CSV of file extensions that this UI will accept. For video embeds you can usevimeo
andyoutube
as the extension.
Supported Datatypes: MANYTOMANY
(an alias datatype)
This is a M2M relational UI that links multiple files (and YouTube/Vimeo video embeds). If you have an album
table you could use this to store mp3s within tracks
, for a projects
table this would be the UI used for columns like: hero_slideshow
, youtube_playlist
, and press_pdfs
. Basically any column that needs to store multiple files. Currently only Directus Files are accepted by this UI, so directus_columns.table_related
must always be set to directus_files
.
add_button
: Toggles an "Add" button for adding new files directly into the UIchoose_button
: Toggles a "Choose" button that opens a modal with all existing Directus files to choose fromremove_button
: Toggles "Remove" buttons for each file that let's you delete it
Supported Datatypes: MANYTOMANY
(an alias datatype)
This is a M2M relational UI that will make it easy to link the item being edited to multiple other items from another table (or the same table). You can use this to relate multiple tags
to projects
, or multiple staff
to their respective office
. But be careful about creating a schema/architecture with recursive or deeply nested M2Ms – otherwise you'll end up with a confusing "Matryoshka doll" user experience.
visible_columns
: A column name (or CSV of column names) to show within the interfaceadd_button
: Toggles an "Add" button for adding new items directly into the UIchoose_button
: Toggles a "Choose" button that opens a modal with existing table items to choose fromremove_button
: Toggles "Remove" buttons for each item that let's you delete itfilter_type
: You have two options for how to filter this relational column from the Item Listing page depending on the size of your dataset:- Dropdown: For small datasets, this gives a dropdown for easy filtering
- Text Input: For larger datasets, this open field let's you filter by typing
filter_column
: The column who's value is used for filteringvisible_column_template
: Handlebars template notation for the fields to show in results. Eg:{{first_name}} {{last_name}}
. All columns used here must be added tovisible_columns
min_entries
: Sets a minimum number of items that need to be added for this field to validateno_duplicates
: If enabled, items already linked will not show up in the Choose Item listing modal
Supported Datatypes: INT
This is a M2O relational UI drop-down that links to a single item by storing the related item's ID in the column – which is why this UI only works with the INT datatype (also used for IDs). You could use this to relate each item in your press
table to a project
, or to relate
readonly
: Disables editing of the field while still letting users see the valuevisible_column
: A column name (or CSV of column names) to show within the interface- TODO: update name to plural, this accepts CSV columns
visible_column_template
: Handlebars template notation for the fields to show in results. Eg:{{first_name}} {{last_name}}
. All columns used here must be added tovisible_columns
visible_status_ids
: The values of the status column that will be shown/allowed in this UI. If the related table has a status column the default values are:0 = deleted
,1 = active
,2 = draft
placeholder_text
: Grayed out default placeholder text in the input when it's emptyfilter_type
: You have two options for how to filter this relational column from the Item Listing page depending on the size of your dataset:- Dropdown: For small datasets, this gives a dropdown for easy filtering
- Text Input: For larger datasets, this open field let's you filter by typing
filter_column
: The column who's value is used for filtering
Supported Datatypes: INT
Similar to the Many-to-One
in function, the interface for this UI is a type-ahead (live search auto-complete) which is useful for large relational datasets that won't fit into a dropdown.
visible_column
: The column name used to search and show for itemssize
: Adjusts the max width of the input (Small, Medium, Large)template
: Handlebars template for displaying the itemsinclude_inactive
: Whether or not to include inactive (2
) status items
Supported Datatypes: ONETOMANY
(an alias datatype)
Similar to Many-to-One, this UI is an interface for the opposite direction. Instead of saving the id
of a related item in an actual column, the One-to-Many is an Alias column that saves a FK on the related items.
visible_columns
: Which columns to show for related itemsresult_limit
: A maximum number of results to be returned before truncating resultsadd_button
: Toggles an "Add" button for adding new items directly into the UIchoose_button
: Toggles a "Choose" button for finding and selecting existing related itemsremove_button
: Toggles "Remove" buttons for each item that let's you delete it (see below)only_unassigned
: Toggles if you can choose any existing related items (reassigns ID when saving), or only ones not assigned to other items (already have an ID)
When deleting these related O2M items, the following rules apply to the related table:
- HAS STATUS COLUMN + FK ALLOW NULL
- Status = NO CHANGE (SAME STATUS), FK = NULL
- HAS STATUS COLUMN + FK DOESN'T ALLOW NULL
- Status = 0 (SOFT DELETE), FK = NO CHANGE (SAME ID)
- NO STATUS COLUMN + FK ALLOW NULL
- FK = NULL
- NO STATUS COLUMN + FK DOESN'T ALLOW NULL
- HARD DELETE ROW (PERMANENT)
Supported Datatypes: ONETOMANY
(an alias datatype)
This relational UI allows for field translations to be stored in a related table. For example, if you have a projects
table you could create a projects_translations
table to relationally store the name
and description
columns in other languages. Some data, such as hero_image
or featured
may not need to be translated and can be added directly to the projects
table.
Example Schema
-
projects
Tableid
– ID of the projectactive
– Status column that determines if project is active/draft/deletedhero_image
– This would be for a non-language dependent imagefeatured
– Non-language dependent checkbox for featuring this project on the homepage
-
projects_translations
Tableid
– ID of the translationproject_id
– ID of the project this is related tolanguage_id
– ID of the language this is written in (PK oflanguages
table)name
– Project name which can be translated into multiple languagesdescription
– Project description which can be translated into multiple languages
-
languages
Tableid
– "primary key" – Can be an ID (eg "1"), or a language identifier (eg "en")language
– Is the written-out name of the language (eg "English")
-
languages_table
: The name of the table that holds the language options -
languages_name_column
: The name of the column in the languages_table with the title of the language option -
default_language_id
: The default ID to use/show from the languages_table -
left_column_name
: The name of the column on the table (egprojects
) that stores the language ID (foreign key)
Relational Options
When creating the translation column within Directus you'll need to enter some info about the relationship. These are some helpful reminders:
user_interface
: This should be set to `translations, obviouslydata_type
: This will automatically be set toALIAS
since this is not an actual field and the data is stored relationallyrelated_table
: This should be the table that will hold the translations (egproject_translations
)junction_column
: This is the column that stores your table ID (eg theprojects
ID) in the related_table