ORMBridge Custom Serializers - Simplified Guide
When to Use Custom Serializers
- For custom field types not natively handled by ORMBridge
- To transform data during serialization/deserialization
- To add validation during deserialization
- To handle complex nested data structures
Creating a Custom Field Serializer
1. Implement the Serializer
python
# Example: Money Field Serializer
from rest_framework import serializers
from djmoney.money import Money
from decimal import Decimal
class MoneyFieldSerializer(serializers.Field):
def to_representation(self, value):
# Convert Money object to dictionary for API
return {
'amount': str(value.amount),
'currency': value.currency.code
}
def to_internal_value(self, data):
# Convert API data back to Money object
if not isinstance(data, dict):
raise serializers.ValidationError("Expected a dictionary with amount and currency")
try:
amount = Decimal(data['amount'])
currency = data['currency']
return Money(amount, currency)
except (KeyError, ValueError):
raise serializers.ValidationError("Invalid money format")
2. Define Schema Override
python
from ormbridge.core.interfaces import AbstractSchemaOverride
from ormbridge.core.classes import FieldType, FieldFormat, SchemaFieldMetadata
class MoneyFieldSchema(AbstractSchemaOverride):
def get_schema(field):
# The key is used as reference in the schema (e.g., "#/components/schemas/MoneyField")
key = field.__class__.__name__ # e.g., "MoneyField"
# Define the JSON Schema structure for this field
definition = {
"type": "object",
"properties": {
"amount": {"type": "number"},
"currency": {"type": "string"}
}
}
# Define metadata about this field type
schema = SchemaFieldMetadata(
type=FieldType.OBJECT,
title="Money",
required=True,
nullable=field.null,
format=FieldFormat.MONEY,
description=field.help_text or "Money field"
)
# Return schema, definition, and reference key
return schema, definition, key
3. Register Your Custom Serializer
python
from djmoney.models.fields import MoneyField
from ormbridge.adaptors.django.config import config
# Register custom field serializer and schema override
config.custom_serializers[MoneyField] = MoneyFieldSerializer
config.schema_overrides[MoneyField] = MoneyFieldSchema
Testing Your Custom Serializer
You can test your custom serializer using the DynamicModelSerializer:
python
from ormbridge.adaptors.django.serializers import DynamicModelSerializer
from your_app.models import ProductWithMoneyField
# Generate a serializer for your model
serializer_class = DynamicModelSerializer.for_model(ProductWithMoneyField)
# Test serialization with an instance
product = ProductWithMoneyField.objects.first()
serializer = serializer_class(product)
serialized_data = serializer.data
print(serialized_data) # Should show your money field properly serialized
# Test deserialization
input_data = {
'name': 'Test Product',
'price': {'amount': '29.99', 'currency': 'USD'}
}
deserializer = serializer_class(data=input_data)
if deserializer.is_valid():
print("Valid data!")
print(deserializer.validated_data) # Should include Money object
else:
print("Validation errors:", deserializer.errors)
Adding Computed Properties (Additional Fields)
python
from django.db import models
from ormbridge.adaptors.django.config import registry
from ormbridge.core.classes import AdditionalField
class Product(models.Model):
price = models.DecimalField(max_digits=10, decimal_places=2)
tax_rate = models.DecimalField(max_digits=5, decimal_places=2, default=0.20)
@property
def price_with_tax(self):
return self.price * (1 + self.tax_rate)
# Register additional fields
registry.register(
Product,
additional_fields=[
AdditionalField(
name="price_with_tax",
field=models.DecimalField(max_digits=10, decimal_places=2),
title="Price Including Tax"
)
]
)
Important: Additional fields are read-only and don't trigger cache invalidation when underlying data changes.