Skip to content

Model hooks

API Documentation

amsdal_models.classes.mixins.model_hooks_mixin.ModelHooksMixin

Model hooks allow you to insert custom logic into models based on certain events. Hooks as seperate python files in the JSON schema defintions, and as methods on the model class

Warning

Do not use .save() or .delete() methods in the hooks, as it may cause and error or unexpected behavior.


The pre_init hook

This hook is called just before the model is initialized and the built-in validations are executed. It accepts is_new_object boolean argument that indicates if the model is being initialized as a new record or existing one.

Also, it accepts kwargs: dict[str, Any] argument that contains the keyword arguments that are passed to the model constructor. Since the kwargs is a dict, you can modify it in the hook and the changes will be applied to the model constructor.

This hook is useful for setting default values for the model fields or for custome ETL or validation of keyword arguments.

Note

At this point the pydantic object is not fully initialized, so you need to check the kwargs for the fields you want to modify.

Example
def pre_init(self, *, is_new_object: bool, kwargs: dict[str, Any]) -> None:
    if is_new_object:
        kwargs['name'] = 'Default Name'

    if kwargs.get('custom_id_field'):
        kwargs['_object_id'] = kwargs['custom_id_field']

The post_init hook

This hook is called just after the model is initialized and the built-in validations are executed. It accepts the same arguments as the pre_init hook.

This hook also is useful for setting default values for the model fields or for extra validation of keyword arguments.

Note

Pydantic object is fully initialized and validated at this point, so you can access the fields directly, and set your custom fields here.

Example
def post_init(self, *, is_new_object: bool, kwargs: dict[str, Any]) -> None:
    if is_new_object:
        self.name = 'Default Name'

    if self.name.islower():
        msg = 'The name should not be written in lowercase'
        raise ValueError(msg)

The pre_create hook

This hook is called just before a new record of a model is saved to the database. It accepts self as a single argument.

This hook is useful for setting default values for the first time before the creation of the object.

Note

At this stage object is not saved yet, so you cannot fetch the object from the database.

Example

def pre_create(self) -> None:
    if not self.name:
        self.name = 'Default Name'

The apre_create hook

This hook is called just before a new record of a model is saved to the database. It accepts self as a single argument.

This hook is useful for setting default values for the first time before the creation of the object.

Note

At this stage object is not saved yet, so you cannot fetch the object from the database.

Example

async def apre_create(self) -> None:
    if not self.name:
        self.name = 'Default Name'


The post_create hook

This hook is called just after the new record of model is saved to the database. It accepts self as a single argument.

This hook is useful for adding extra logic after the model is saved to the database. For example, sending a notification or starting a datapipeline to create additional records.

Example

def post_create(self) -> None:
    PersonProfile(person=self).save()

The apost_create hook

This hook is called just after the new record of model is saved to the database. It accepts self as a single argument.

This hook is useful for adding extra logic after the model is saved to the database. For example, sending a notification or starting a datapipeline to create additional records.

Example

async def apost_create(self) -> None:
    await PersonProfile(person=self).asave()


The pre_update hook

This hook is called just before the existing record of model is updated in the database. It accepts self as a single argument.

This hook is useful for validating the model before updating it in the database.

Note

Object version is not changed yet, so to check original version of the object to compare fields use .refetch_from_db() method.

Example

def pre_update(self) -> None:
    original_object = self.refetch_from_db()

    if original_object.name != self.name:
        msg = 'You cannot change the name of the object'
        raise ValueError(msg)

The apre_update hook

This hook is called just before the existing record of model is updated in the database. It accepts self as a single argument.

This hook is useful for validating the model before updating it in the database.

Note

Object version is not changed yet, so to check original version of the object to compare fields use .refetch_from_db() method.

Example

async def apre_update(self) -> None:
    original_object = await self.arefetch_from_db()

    if original_object.name != self.name:
        msg = 'You cannot change the name of the object'
        raise ValueError(msg)


The post_update hook

This hook is called just after the existing record of model is updated in the database. It accepts self as a single argument.

This hook is useful for adding extra logic after the model is updated in the database. For example, sending a notification or starting a datapipeline to create additional records.

Example

def post_update(self) -> None:
    send_email(email=self.email, subject=f'Hi, {self.name}! Your profile has been updated')

The apost_update hook

This hook is called just after the existing record of model is updated in the database. It accepts self as a single argument.

This hook is useful for adding extra logic after the model is updated in the database. For example, sending a notification or starting a datapipeline to create additional records.

Example

async def apost_update(self) -> None:
    send_email(email=self.email, subject=f'Hi, {self.name}! Your profile has been updated')


The pre_delete hook

This hook is called just before the existing record of model is deleted from the database. It accepts self as a single argument.

This hook is useful if you want to check if the record can be deleted or not.

Example

def pre_delete(self) -> None:
    if self.account_balance < 0:
        msg = 'You cannot delete the record with negative balance'
        raise ValueError(msg)

The apre_delete hook

This hook is called just before the existing record of model is deleted from the database. It accepts self as a single argument.

This hook is useful if you want to check if the record can be deleted or not.

Example

astbc def apre_delete(self) -> None:
    if self.account_balance < 0:
        msg = 'You cannot delete the record with negative balance'
        raise ValueError(msg)


The post_delete hook

This hook is called just after the existing record of model is deleted from the database. It accepts self as a single argument.

This hook is useful for adding extra logic after the model is deleted from the database. For example, you can send a notification to the user that the record is deleted.

Example

def post_delete(self) -> None:
    send_email(email=self.email, subject=f'Hi, {self.name}! Your profile has been deleted')

The apost_delete hook

This hook is called just after the existing record of model is deleted from the database. It accepts self as a single argument.

This hook is useful for adding extra logic after the model is deleted from the database. For example, you can send a notification to the user that the record is deleted.

Example

async def apost_delete(self) -> None:
    send_email(email=self.email, subject=f'Hi, {self.name}! Your profile has been deleted')


Info

You can read more about hooks in the AMSDAL CLI documentation.