# UUID Serialization Best Practices Guide

## Quick Reference

### Problem
UUID objects cannot be directly serialized to JSON in Python.

### Solution
Always convert UUID fields to strings before serialization.

## Common Scenarios

### Scenario 1: Creating Data Dictionaries

```python
# ❌ WRONG - Will cause TypeError
loan_data = {
    'id': loan.id,  # UUID object
    'product_id': loan.product.id  # UUID object
}

# ✅ CORRECT - JSON serializable
loan_data = {
    'id': str(loan.id),  # String
    'product_id': str(loan.product.id)  # String
}
```

### Scenario 2: Passing Querysets to Templates

```python
# ❌ WRONG - May cause issues in template JSON serialization
loan_products = LoanProduct.objects.all()
context = {'loan_products': loan_products}

# ✅ CORRECT - Use list of dictionaries
loan_products_qs = LoanProduct.objects.all()
loan_products = [
    {
        'id': str(p.id),
        'name': p.name,
        'product_type': p.product_type
    }
    for p in loan_products_qs
]
context = {'loan_products': loan_products}
```

### Scenario 3: JsonResponse Views

```python
from django.http import JsonResponse

# ❌ WRONG - Will fail on UUID fields
def my_api_view(request):
    loans = Loan.objects.filter(status='active')
    data = list(loans.values())  # Contains UUID objects
    return JsonResponse(data, safe=False)

# ✅ CORRECT - Convert UUIDs to strings
def my_api_view(request):
    loans = Loan.objects.filter(status='active')
    data = [
        {
            'id': str(loan.id),
            'loan_number': loan.loan_number,
            'amount': float(loan.principal_amount)
        }
        for loan in loans
    ]
    return JsonResponse(data, safe=False)
```

### Scenario 4: URL Parameters and Filters

```python
# ❌ WRONG - UUID in context
context = {
    'selected_product_id': product_id  # UUID object
}

# ✅ CORRECT - Convert to string
context = {
    'selected_product_id': str(product_id) if product_id else None
}
```

## Models with UUID Fields

The following models in this project use UUID primary keys:

- `Loan` - `id` field
- `LoanProduct` - `id` field
- `LoanApplication` - `id` field (if applicable)

Always convert these when serializing!

## Testing for UUID Issues

### Quick Test
```python
import json

# Test your data dictionary
try:
    json.dumps(my_data_dict)
    print("✅ Serialization successful")
except TypeError as e:
    print(f"❌ Serialization failed: {e}")
```

### Add to Views
```python
# For JSON format endpoints
if request.GET.get('format') == 'json':
    try:
        return JsonResponse(context, safe=False)
    except TypeError as e:
        # Log the error with details
        logger.error(f"JSON serialization error: {e}")
        logger.error(f"Context keys: {context.keys()}")
        return JsonResponse({'error': 'Serialization error'}, status=500)
```

## Django JSON Encoder Alternative

For complex serialization needs, use Django's built-in encoder:

```python
from django.core.serializers.json import DjangoJSONEncoder
import json

data_with_uuids = {
    'id': loan.id,  # UUID
    'date': timezone.now(),  # datetime
    'amount': Decimal('100.50')  # Decimal
}

# Use DjangoJSONEncoder
json_string = json.dumps(data_with_uuids, cls=DjangoJSONEncoder)
```

## Template Usage

### In Django Templates
```django
{# UUID fields should be pre-converted in view #}
{% for product in loan_products %}
    <option value="{{ product.id }}">{{ product.name }}</option>
{% endfor %}
```

### In JavaScript/JSON Script Tags
```django
<script>
const products = {{ loan_products|safe }};
// Products should already have string IDs from view conversion
</script>
```

## Common Errors and Fixes

### Error 1: "Object of type UUID is not JSON serializable"
**Fix:** Convert UUID to string: `str(uuid_value)`

### Error 2: Queryset not serializable
**Fix:** Convert to list of dictionaries with converted UUIDs

### Error 3: Nested UUIDs in related objects
```python
# ❌ WRONG
data = {
    'loan': loan,  # Has UUID fields
    'product': loan.product  # Has UUID fields
}

# ✅ CORRECT
data = {
    'loan': {
        'id': str(loan.id),
        'number': loan.loan_number
    },
    'product': {
        'id': str(loan.product.id),
        'name': loan.product.name
    }
}
```

## Checklist for New Views

When creating a new view that returns JSON or uses templates:

- [ ] Check all model IDs and convert UUIDs to strings
- [ ] Convert querysets to lists of dictionaries if needed
- [ ] Convert URL parameters that might be UUIDs
- [ ] Test with `?format=json` if applicable
- [ ] Verify dropdown/select elements work
- [ ] Check export functions (PDF/Excel)
- [ ] Test with actual data, not just empty results

## Performance Notes

- String conversion is very fast (`str(uuid)`)
- Consider caching if converting large datasets repeatedly
- List comprehensions are efficient for bulk conversions
- No database performance impact (conversion happens in Python)

## Related Documentation

- Django JSON Serialization: https://docs.djangoproject.com/en/stable/topics/serialization/
- Python UUID module: https://docs.python.org/3/library/uuid.html
- DjangoJSONEncoder: https://docs.djangoproject.com/en/stable/topics/serialization/#djangojsonencoder

## Questions?

If you encounter UUID serialization issues:
1. Check if the field is a UUIDField in the model
2. Convert to string: `str(uuid_field)`
3. Test JSON serialization: `json.dumps(data)`
4. Review this guide for patterns
5. Check git history for similar fixes

---

**Last Updated:** July 11, 2026  
**Related Fix:** UUID_FIX_COMPLETE_SUMMARY.md
