2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-16 12:05:53 +00:00
Files
InvenTree/docs/docs/extend/plugins/metadata.md
Oliver f6123cc261 [WIP] docker / Caddy (#6551)
* remove docker-sqlite file

- Do not want to encourage use of sqlite

* Add Caddyfile

* Add default site URL to .env

- Matches Caddyfile

* Cleanup / simplify .env file

* Remove dev nginx conf file

* Further cleanup of .env file

* Update docker-compose.yml

- Use caddy image instead of nginx as proxy

* Set max body size

* gunicorn: enable external logging

* Update file structure

* Cleanup docker-compose file

* Update docker/docker-compose.yml

Co-authored-by: Matthias Mair <code@mjmair.com>

* Update docker/Caddyfile

Co-authored-by: Matthias Mair <code@mjmair.com>

* Fix for postgresql packages

- Need postgresql13-client to be installed, it contains pg_dump
- Without this, backup / restore *does not work*

* Create static_i18n dir if it does not exist

* Reduce output from collectstatic

* Revert gunicorn logging

- Want to see the logs in docker

* Fix trailing slash

Ref: https://github.com/inventree/InvenTree/pull/6551#issuecomment-1962423765

* tasks.py - pass 'nouv' option through

* Update package requirements:

- Allow installation of rapidfuzz without building

* Install uv as part of docker image

* Add environment variable to control downstream URL

* Do not use uv package manager by default

- Currently does not work "correctly" - ignores installed packages
- Requires further work to run reliably

* Fix docker-compose file

- Do not build locally

* Cleanup gunicorn file

- Remove unused lien

* Cleanup docker-compose.yml

- Simpler volume management

* Update Caddyfile

Add newline

* Update requirements.txt

Add newline

* Update tasks.py

Add missing blank line

* Simplify Caddyfile

* Adds option for customizing web port

* cleanup docker-compose.yml

- Better mapping of caddy data
- Cleaner volume setup

* Add django version template

- Ensure all docs links point to the current django version we are using

* docs: cleanup intro.md

* Cleanup serving_files.md

* Cleanup config.md

* docker install docs updates

* Enable code block copying

* Fix include file

* Fix link

* Update docker install docs

* Update docker.md

* Add info about demo dataset

* Tweak heading

* Update docs link checks

* Fix workflow

* Another fix

* More ignore pattearns

---------

Co-authored-by: Matthias Mair <code@mjmair.com>
2024-02-28 01:06:19 +11:00

132 lines
4.2 KiB
Markdown

---
title: Model Metadata
---
## Model Metadata
Plugins have access to internal database models (such at [Parts](../../part/part.md)), 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](./app.md). 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]({% include "django.html" %}/ref/models/fields/#django.db.models.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.
!!! tip "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:
```python
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:
{% with id="metadata_api", url="plugin/model_metadata_api.png", description="Access model metadata via API", maxheight="400px" %}
{% include 'img.html' %}
{% endwith %}
#### 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:**
```json
{"foo": "bar", "hello": "world"}
```
**Payload:**
```json
{"xyz": "XYZ"}
```
**Result of PUT request:**
```json
{"xyz: XYZ"}
```
**Result of PATCH request:**
```json
{"foo": "bar", "hello": "world", "xyz": "XYZ"}
```
!!! danger "Take Care"
Take care when updating metadata via the API, especially when using a PUT request.
### Python API Access
The [Python API library](../../api/python/python.md) provides similar support for accessing model metadata. Use the `setMetadata` method to retrieve metadata information from the server:
```python
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:
```python
part.setMetadata("abc", "xyz")
print(part.getMetadata())
> {'abc': 'xyz', 'foo': 'bar', 'hello': 'world'}
```
!!! tip "Merge vs Overwrite"
By default setting a metadata `key:value` pair will *merge* data in with existing data, by using a [PATCH request](#put-vs-patch).
To *overwrite* existing metadata, use the `overwrite=True` flag:
```python
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](../plugins/app.md) to develop custom database tables for your data.