Custom Fields¶
Custom fields allow you to extend CRM models with user-defined attributes. Field definitions are stored separately from the data, and values are validated automatically on create and update.
CustomFieldDefinition¶
Defines a custom field that can be added to a CRM model.
| Field | Type | Default | Description |
|---|---|---|---|
entity_type |
See below | required | Which model this field applies to |
field_name |
str |
required | Field identifier (unique per entity type) |
field_label |
str |
required | Human-readable label |
field_type |
Literal['text', 'number', 'date', 'choice'] |
required | Value type |
choices |
list[str] \| None |
None |
Allowed values (for choice type) |
is_required |
bool |
False |
Whether the field is required |
default_value |
Any \| None |
None |
Default value |
help_text |
str \| None |
None |
Help text for UI display |
display_order |
int |
0 |
Display order in UI |
There is a unique constraint on (entity_type, field_name).
Supported Entity Types¶
Custom fields can be defined for these models:
EntityEntityRelationshipDealEntityIdentifierEntityContactPointEntityAddress
Example¶
from amsdal_crm.models.custom_field_definition import CustomFieldDefinition
# Define a text field for entities
CustomFieldDefinition(
entity_type='Entity',
field_name='industry',
field_label='Industry',
field_type='text',
is_required=False,
help_text='Primary industry sector',
display_order=1,
).save(force_insert=True)
# Define a choice field for deals
CustomFieldDefinition(
entity_type='Deal',
field_name='deal_source',
field_label='Deal Source',
field_type='choice',
choices=['Inbound', 'Outbound', 'Referral', 'Partner'],
is_required=True,
display_order=2,
).save(force_insert=True)
CustomFieldsMixin¶
The CustomFieldsMixin adds a custom_fields dict to models and hooks into the create/update lifecycle for automatic validation.
Models that include this mixin: Entity, EntityRelationship, Deal, EntityIdentifier, EntityContactPoint, EntityAddress.
Setting Custom Field Values¶
from amsdal_crm.models.entity import Entity
entity = Entity(
name='Acme Corp',
custom_fields={
'industry': 'Technology',
},
)
entity.save(force_insert=True) # custom_fields validated via pre_create hook
How Validation Works¶
On every pre_create and pre_update, the mixin calls CustomFieldService.validate_custom_fields() which:
- Loads all
CustomFieldDefinitionrecords for the model's entity type - Rejects any field names not defined in definitions (
CustomFieldValidationError) - Checks required fields are present and not
None - Validates and converts values by type
Type Validation¶
| Field Type | Validation | Conversion |
|---|---|---|
text |
Accepts any value | Converts to str |
number |
Must be a valid number | Converts to Decimal |
date |
Must be a valid ISO date | Parses and re-serializes as ISO format |
choice |
Must be in the choices list |
No conversion |
Invalid values raise CustomFieldValidationError:
from amsdal_crm.errors import CustomFieldValidationError
Configuration¶
The maximum number of custom field definitions per entity type is controlled by:
AMSDAL_CRM_MAX_CUSTOM_FIELDS_PER_ENTITY=50 # default