Skip to content

Model Metadata

Model Metadata

Plugins have access to internal database models (such at Parts), and any associated data associated with these models. It may be the case that a particular plugin needs to store some extra information about a particular model instance, to be able to perform custom functionality.

One way of achieving this would be to create an entirely new database model to keep track of this information, using the app plugin mixin. However, this is a very heavy-handed (and complicated) approach!

A much simpler and more accessible method of recording custom information against a given model instance is provided "out of the box" - using Model Metadata.

MetadataMixin Class

Most of the models in the InvenTree database inherit from the MetadataMixin class, which adds the metadata field to each inheriting model. The metadata field is a JSONField which allows for storing arbitrary JSON data against the model instance.

This field is provided to allow any plugins to store and retrieve arbitrary data against any item in the database.

External Use Only

It is important to note that the metadata field of each model instance is not used for any internal functionality. Any data stored against this field is only for use by external plugins.

Accessing Metadata

Plugin Access

The metadata field can be accessed and updated directly from custom plugin code, as follows:

from part.models import Part

# Show metadata value against a particular Part instance
part = Part.objects.get(pk=100)
print(part.metadata)

> {'foo': 'bar'}

part.metadata['hello'] = 'world'
print(part.metadata)

> {'foo': 'bar', 'hello': 'world'}

API Access

For models which provide this metadata field, access is also provided via the API. Append /metadata/ to the detail endpoint for a particular model instance to access.

For example:

Access model metadata via API Access model metadata via API

PUT vs PATCH

An important note with regard to metadata access via the API is the behaviour of a PUT request vs a PATCH request. As demonstrated in the comparison below, a PUT request will overwrite existing data, while a PATCH request will merge with existing data.

Initial Data:

{"foo": "bar", "hello": "world"}

Payload:

{"xyz": "XYZ"}

Result of PUT request:

{"xyz: XYZ"}

Result of PATCH request:

{"foo": "bar", "hello": "world", "xyz": "XYZ"}

Take Care

Take care when updating metadata via the API, especially when using a PUT request.

Python API Access

The Python API library provides similar support for accessing model metadata. Use the setMetadata method to retrieve metadata information from the server:

from inventree.api import InvenTreeAPI
from inventree.part import Part

api = InvenTreeAPI("http://localhost:8000", username="admin", password="inventree")

part = Part(api, pk=100)

print(part.getMetadata())

> {'foo': 'bar', 'hello': 'world'}

Metadata can be added directly here using the setMetadata method:

part.setMetadata("abc", "xyz")

print(part.getMetadata())

> {'abc': 'xyz', 'foo': 'bar', 'hello': 'world'}

Merge vs Overwrite

By default setting a metadata key:value pair will merge data in with existing data, by using a PATCH request.

To overwrite existing metadata, use the overwrite=True flag:

part.setMetadata({"aaa": "ABC"}, overwrite=True)

print(part.getMetadata())
> {'aaa': 'ABC'}

Considerations

Data Keys

There is no guarantee that the data added to a particular model will not be overwritten by a different plugin. Your plugin should at least ensure that the data keys used are unique to the plugin, to ensure that they do not conflict with other plugins

Structured Data

If you need to store data which is more "structured" than JSON objects, consider using the (more complex) app mixin to develop custom database tables for your data.


Last update: December 15, 2023