LogixVast

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 value

Pagination

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