---
title: Charmhub | Deploy Data Platform Libs using Charmhub - The Open Operator Collection
description: Deploy the latest version of Data Platform Libs on any cloud.
url: https://charmhub.io/data-platform-libs/libraries/data_models
---

# Data Platform Libs

[Canonical](https://charmhub.io/publisher/data-platform "View all packages from Canonical")

* [Canonical](https://charmhub.io/publisher/data-platform "View all packages from Canonical")
* [Databases](https://charmhub.io/?filter=databases)

Platform:

22.04

stable 81

```
juju deploy data-platform-libs
```

[Learn to deploy on juju >](https://juju.is/docs/juju/manage-applications)

[Toggle side navigation](https://charmhub.io/data-platform-libs/libraries/data_models#drawer)

## charms.data\_platform\_libs.v1.data\_models

* [*Docstrings*Docstrings](https://charmhub.io/data-platform-libs/libraries/data_models)
  [*Code*Source code](https://charmhub.io/data-platform-libs/libraries/data_models/source-code)
* + Download

    Fetch library

    ```
    charmcraft fetch-lib charms.data_platform_libs.v1.data_models
    ```

    [Download data\_models.py](https://charmhub.io/data-platform-libs/libraries/data_models/download)
  + *Last updated* 28 May 2025
  + *Revision* Library version 1.0

Library to provide simple API for promoting typed, validated and structured dataclass in charms.

Dict-like data structure are often used in charms. They are used for config, action parameters
and databag. This library aims at providing simple API for using pydantic BaseModel-derived class
in charms, in order to enhance:

* Validation, by embedding custom business logic to validate single parameters or even have
  validators that acts across different fields
* Parsing, by loading data into pydantic object we can both allow for other types (e.g. float) to
  be used in configuration/parameters as well as specify even nested complex objects for databags
* Static typing checks, by moving from dict-like object to classes with typed-annotated properties,
  that can be statically checked using mypy to ensure that the code is correct.

Pydantic models can be used on:

* Charm Configuration (as defined in config.yaml)
* Actions parameters (as defined in actions.yaml)
* Application/Unit Databag Information (thus making it more structured and encoded)

##### Creating models

Any data-structure can be modeled using dataclasses instead of dict-like objects (e.g. storing
config, action parameters and databags). Within pydantic, we can define dataclasses that provides
also parsing and validation on standard dataclass implementation:

```
from charms.data_platform_libs.v1.data_models import BaseConfigModel

class MyConfig(BaseConfigModel):

    my_key: int

    @validator("my_key")
     def is_lower_than_100(cls, v: int):
         if v > 100:
             raise ValueError("Too high")
```

This should allow to collapse both parsing and validation as the dataclass object is parsed and
created:

```
dataclass = MyConfig(my_key="1")

dataclass.my_key # this returns 1 (int)
dataclass["my_key"] # this returns 1 (int)

dataclass = MyConfig(my_key="102") # this returns a ValueError("Too High")
```

##### Charm Configuration Model

Using the class above, we can implement parsing and validation of configuration by simply
extending our charms using the `TypedCharmBase` class, as shown below.

```
class MyCharm(TypedCharmBase[MyConfig]):
    config_type = MyConfig

     # everywhere in the code you will have config property already parsed and validate
     def my_method(self):
         self.config: MyConfig
```

##### Action parameters

In order to parse action parameters, we can use a decorator to be applied to action event
callbacks, as shown below.

```
@validate_params(PullActionModel)
def _pull_site_action(
    self, event: ActionEvent,
    params: Optional[Union[PullActionModel, ValidationError]] = None
):
    if isinstance(params, ValidationError):
        # handle errors
    else:
        # do stuff
```

Note that this changes the signature of the callbacks by adding an extra parameter with the parsed
counterpart of the `event.params` dict-like field. If validation fails, we return (not throw!) the
exception, to be handled (or raised) in the callback.

##### Databag

In order to parse databag fields, we define a decorator to be applied to base relation event
callbacks.

```
@parse_relation_data(app_model=AppDataModel, unit_model=UnitDataModel)
def _on_cluster_relation_joined(
        self, event: RelationEvent,
        app_data: Optional[Union[AppDataModel, ValidationError]] = None,
        unit_data: Optional[Union[UnitDataModel, ValidationError]] = None
) -> None:
    ...
```

The parameters `app_data` and `unit_data` refers to the databag of the entity which fired the
RelationEvent.

When we want to access to a relation databag outsides of an action, it can be useful also to
compact multiple databags into a single object (if there are no conflicting fields), e.g.

```
class ProviderDataBag(BaseClass):
    provider_key: str

class RequirerDataBag(BaseClass):
    requirer_key: str

class MergedDataBag(ProviderDataBag, RequirerDataBag):
    pass

merged_data = get_relation_data_as(
    MergedDataBag, relation.data[self.app], relation.data[relation.app]
)

merged_data.requirer_key
merged_data.provider_key
```

The above code can be generalized to other kinds of merged objects, e.g. application and unit, and
it can be extended to multiple sources beyond 2:

```
merged_data = get_relation_data_as(
    MergedDataBag, relation.data[self.app], relation.data[relation.app], ...
)
```

---

Index

* [class BaseConfigModel](https://charmhub.io/data-platform-libs/libraries/data_models#baseconfigmodel)
* + [def \_\_getitem\_\_(
    self,
    x)](https://charmhub.io/data-platform-libs/libraries/data_models#baseconfigmodel-__getitem__)
* [class TypedCharmBase](https://charmhub.io/data-platform-libs/libraries/data_models#typedcharmbase)
* + [def config(
    self)](https://charmhub.io/data-platform-libs/libraries/data_models#typedcharmbase-config)
* [def validate\_params(
  cls
  )](https://charmhub.io/data-platform-libs/libraries/data_models#validate_params)
* + [def decorator(
    f)](https://charmhub.io/data-platform-libs/libraries/data_models#validate_params-decorator)
* [def write(
  relation\_data,
  model
  )](https://charmhub.io/data-platform-libs/libraries/data_models#write)
* [def read(
  relation\_data,
  obj
  )](https://charmhub.io/data-platform-libs/libraries/data_models#read)
* [def parse\_relation\_data(
  app\_model,
  unit\_model
  )](https://charmhub.io/data-platform-libs/libraries/data_models#parse_relation_data)
* + [def decorator(
    f)](https://charmhub.io/data-platform-libs/libraries/data_models#parse_relation_data-decorator)
* [class RelationDataModel](https://charmhub.io/data-platform-libs/libraries/data_models#relationdatamodel)
* + [def write(
    self,
    relation\_data)](https://charmhub.io/data-platform-libs/libraries/data_models#relationdatamodel-write)
* + [def read(
    cls,
    relation\_data)](https://charmhub.io/data-platform-libs/libraries/data_models#relationdatamodel-read)
* [def get\_relation\_data\_as(
  model\_type
  )](https://charmhub.io/data-platform-libs/libraries/data_models#get_relation_data_as)

#### class BaseConfigModel

Description

Class to be used for defining the structured configuration options. None

Methods

BaseConfigModel.
\_\_getitem\_\_(

*self*

,
x
)

Description

Return the item using the notation instance[key]. None

#### class TypedCharmBase

Description

Class to be used for extending config-typed charms. None

Methods

TypedCharmBase.
config(

*self*
)

Description

Return a config instance validated and parsed using the provided pydantic class. None

#### def validate\_params(cls)

Return a decorator to allow pydantic parsing of action parameters.

Arguments

cls

Pydantic class representing the model to be used for parsing the content of the
action parameter

Methods

validate\_params.
decorator(

f
)

#### def write(     relation\_data: RelationDataContent,     model: BaseModel )

Write the data contained in a domain object to the relation databag.

Arguments

relation\_data

pointer to the relation databag

model

instance of pydantic model to be written

#### def read(     relation\_data,     obj )

Read data from a relation databag and parse it into a domain object.

Arguments

relation\_data

pointer to the relation databag

obj

pydantic class representing the model to be used for parsing

#### def parse\_relation\_data(     app\_model,     unit\_model )

Return a decorator to allow pydantic parsing of the app and unit databags.

Arguments

app\_model

Pydantic class representing the model to be used for parsing the content of the
app databag. None if no parsing ought to be done.

unit\_model

Pydantic class representing the model to be used for parsing the content of the
unit databag. None if no parsing ought to be done.

Methods

parse\_relation\_data.
decorator(

f
)

#### class RelationDataModel

Description

Base class to be used for creating data models to be used for relation databags. None

Methods

RelationDataModel.
write(

*self*

,
relation\_data: RelationDataContent
)

Write data to a relation databag.

Arguments

relation\_data

pointer to the relation databag

RelationDataModel.
read(

cls

,
relation\_data: RelationDataContent
)

Read data from a relation databag and parse it as an instance of the pydantic class.

Arguments

relation\_data

pointer to the relation databag

#### def get\_relation\_data\_as(model\_type)

Return a merged representation of the provider and requirer databag into a single object.

Arguments

model\_type

pydantic class representing the merged databag

relation\_data

list of RelationDataContent of provider/requirer/unit sides
