@ -1,101 +1,14 @@
|
||||
---
|
||||
title: Model History
|
||||
description: Centurion ERP Model History development documentation
|
||||
title: Model Audit History
|
||||
description: Centurion ERP Model Audit History development documentation
|
||||
date: 2025-02-15
|
||||
template: project.html
|
||||
about: https://github.com/nofusscomputing/centurion_erp
|
||||
---
|
||||
|
||||
Model History is a core feature that is intended to be used to keep an audit history of **ALL** changes to a model. All Tenancy Models are to have a history model created for it.
|
||||
Model Audit History is a core feature that is intended to be used to keep an audit history of **ALL** changes to a model. All Tenancy Models are to have a history model created for it.
|
||||
|
||||
|
||||
## Adding History to a Model
|
||||
|
||||
Most of the work has already been done, all that is required to add history to a model is the creation of the following:
|
||||
|
||||
- Model
|
||||
|
||||
- Function `get_serialized_model` added to audit model _(parent model only)_
|
||||
|
||||
- Function `get_serialized_child_model` added to audit model _(child model only)_
|
||||
|
||||
- _(child model only)_ model name added to list attribute in `core.models.model_history.ModelHistory.child_history_models`
|
||||
|
||||
!!! tip
|
||||
To obtain the model name you can use the api at endpoint `api/v2/base/content_type` and then filtering by app_name and model. The value in the model field is what's required.
|
||||
|
||||
|
||||
### Model
|
||||
|
||||
The model must inherit from `core.models.model_history.ModelHistory`. This model requires a `models.ForeignKey` field named `model` be added to the new history model that will be receiving the history feature. The foriegn key relationship is to the model that will be receiving the history. There is also a requirement to add a function called `get_serialized_model` that returns the serialized model, using the "base" serializer. The model that is serialized is the model the history is for,
|
||||
|
||||
As history can be broken up into parent-child relationships, if the model in question is a child model. The history model that will then be inherited from is the parent model history class. As this class will already contain the field `model`, the child history class must add field `child_model` which like the field `model` is also a `models.ForeignKey`.
|
||||
|
||||
Like the parent history model, A serializer is required. In this case the serializer function is to be called `get_serialized_child_model` that returns the serialized child model. Again like the parent history model using the "base" serializer. The model that is serialized is the child model the history is for,
|
||||
|
||||
|
||||
#### Example model
|
||||
|
||||
This example is for adding history to the Device Model
|
||||
|
||||
``` py title="models/device_history.py"
|
||||
|
||||
--8<-- "app/itam/models/device_history.py"
|
||||
|
||||
```
|
||||
|
||||
This example is for adding history to the child model DeviceSoftware
|
||||
|
||||
``` py title="models/device_software_history.py"
|
||||
|
||||
--8<-- "app/itam/models/device_software_history.py"
|
||||
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Take note of the inheritence and the fact that children don't override parent objects.
|
||||
|
||||
!!! danger "Requirement"
|
||||
Ensure that for the `model` and `child_model` fields that they are called with `related_name = history`. This ensures that **ALL** models that have history, will have an attribute called `history` that is available when working with that model.
|
||||
|
||||
|
||||
## Audit Model
|
||||
|
||||
For history to save, there is a requirement to add a function to the model being audited. This function is to be called `save_history`. The sole purpose of this function is to call the super class (History class) function of the same name, although this time passing the history model.
|
||||
|
||||
Example of the required function, in this case for the `Device` model.
|
||||
|
||||
``` py
|
||||
|
||||
|
||||
def save_history(self, before: dict, after: dict) -> bool:
|
||||
|
||||
from itam.models.device_history import DeviceHistory
|
||||
|
||||
history = super().save_history(
|
||||
before = before,
|
||||
after = after,
|
||||
history_model = DeviceHistory
|
||||
)
|
||||
|
||||
return history
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
As with any other object within Centurion, the addition of a feature requires it be tested. The following Test Suites are available:
|
||||
|
||||
- `Unit`
|
||||
- `core.tests.unit.test_history.test_unit_history_model.ModelHistoryInheritedCases` History Models
|
||||
|
||||
- `core.tests.abstract.test_unit_model_history_api_v2.PrimaryModelHistoryAPI` for parent / Primary history model
|
||||
|
||||
- `core.tests.abstract.test_unit_model_history_api_v2.ChildModelHistoryAPI` for child history model
|
||||
|
||||
- `Functional` - History entry checks
|
||||
|
||||
- `core.tests.abstract.test_functional_history.HistoryEntriesCommon` for parent / Primary history model
|
||||
|
||||
- `core.tests.abstract.test_functional_history.HistoryEntriesChildModel` for child history model
|
||||
By default there is nothing that you need to do to add Audit History to a model. By virtue of inheriting from [`core.models.centurion.CenturionModel`](../api/models/centurion.md) or [`core.models.centurion.CenturionSubModel`](../api/models/centurion_sub.md) the model will have audit history setup automagically. This wizardry of the machine creates all of the necessary components that the moment you run the migrations the model has a fully functioning audit history system.
|
||||
|
Reference in New Issue
Block a user