Data Serialization
LogixVast APIs use Django REST framework's serialization system to convert complex data types like Django models into JSON format and vice versa.
Model Serialization
Here's how we structure our data using Django REST framework serializers:
Vehicle Model Example
# models.py
from django.db import models
class Vehicle(models.Model):
plate_number = models.CharField(max_length=20, unique=True)
vehicle_type = models.CharField(max_length=50)
manufacturer = models.CharField(max_length=100)
model = models.CharField(max_length=100)
year = models.IntegerField()
status = models.CharField(max_length=20)
last_maintenance = models.DateTimeField(null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
# serializers.py
from rest_framework import serializers
class VehicleSerializer(serializers.ModelSerializer):
class Meta:
model = Vehicle
fields = [
'id', 'plate_number', 'vehicle_type',
'manufacturer', 'model', 'year', 'status',
'last_maintenance', 'created_at', 'updated_at'
]
read_only_fields = ['id', 'created_at', 'updated_at']Nested Serialization
For related models, we use nested serializers to include associated data:
class MaintenanceTask(models.Model):
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE)
task_type = models.CharField(max_length=100)
description = models.TextField()
scheduled_date = models.DateTimeField()
completed = models.BooleanField(default=False)
class MaintenanceTaskSerializer(serializers.ModelSerializer):
class Meta:
model = MaintenanceTask
fields = ['id', 'task_type', 'description', 'scheduled_date', 'completed']
class VehicleDetailSerializer(serializers.ModelSerializer):
maintenance_tasks = MaintenanceTaskSerializer(many=True, read_only=True)
class Meta:
model = Vehicle
fields = [
'id', 'plate_number', 'vehicle_type',
'manufacturer', 'model', 'year', 'status',
'last_maintenance', 'maintenance_tasks',
'created_at', 'updated_at'
]Custom Fields
We can add computed fields or custom logic to our serializers:
class VehicleSerializer(serializers.ModelSerializer):
days_since_maintenance = serializers.SerializerMethodField()
maintenance_status = serializers.SerializerMethodField()
class Meta:
model = Vehicle
fields = [
'id', 'plate_number', 'status',
'days_since_maintenance', 'maintenance_status'
]
def get_days_since_maintenance(self, obj):
if not obj.last_maintenance:
return None
return (timezone.now() - obj.last_maintenance).days
def get_maintenance_status(self, obj):
days = self.get_days_since_maintenance(obj)
if days is None:
return 'unknown'
return 'good' if days < 30 else 'needs_maintenance'Validation
Serializers handle data validation with built-in and custom validators:
def validate_year(value):
current_year = timezone.now().year
if value > current_year:
raise serializers.ValidationError(
f"Year cannot be greater than {current_year}"
)
return value
class VehicleSerializer(serializers.ModelSerializer):
class Meta:
model = Vehicle
fields = '__all__'
validators = [
UniqueTogetherValidator(
queryset=Vehicle.objects.all(),
fields=['manufacturer', 'model', 'plate_number']
)
]
def validate_plate_number(self, value):
if not re.match(r'^[A-Z0-9]{6,8}$', value):
raise serializers.ValidationError(
"Plate number must be 6-8 characters of uppercase letters and numbers"
)
return valuePagination
Our APIs use pagination to handle large datasets efficiently:
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
}
# Example response
{
"count": 1234,
"next": "http://api.example.org/vehicles/?page=2",
"previous": null,
"results": [
{
"id": 1,
"plate_number": "ABC123",
...
},
...
]
}Performance Optimization
We optimize serializer performance using several techniques:
- Select Related: Pre-fetch related objects to avoid N+1 queries
- Prefetch Related: Efficiently load many-to-many and reverse foreign key relationships
- Deferred Loading: Load only required fields for better performance
class VehicleViewSet(viewsets.ModelViewSet):
def get_queryset(self):
return Vehicle.objects.select_related('owner')\
.prefetch_related('maintenance_tasks')\
.defer('description', 'notes')\
.all()Best Practices
- Use ModelSerializers when possible for automatic field mapping
- Implement proper validation at the serializer level for data integrity
- Use nested serializers judiciously to avoid performance issues
- Cache complex computed fields that don't require real-time updates
- Always specify explicit fields rather than using
fields = '__all__' - Use appropriate pagination for large datasets