adrf's async serializers reimplement representation/validation asynchronously, and
several open issues show how hard that surface is to keep correct (#86 — optional
fields silently dropped from validate in async context; #55, #78 —
SynchronousOnlyOperation in ato_representation paths).
In production we've had good results with a deliberately smaller approach: keep the
serializers 100% sync DRF (proven code paths — nested serializers, base64 fields,
to_representation, create/update all unchanged) and bridge only the entry
points through a thread, which is exactly what perform_acreate/perform_aupdate
need:
from asgiref.sync import sync_to_async
class AsyncBridgeMixin:
"""Use a plain sync DRF serializer from async viewsets: only save/validate
hop through a thread; everything else stays sync DRF."""
async def ais_valid(self, **kwargs):
return await sync_to_async(self.is_valid)(**kwargs)
async def asave(self, **kwargs):
return await sync_to_async(self.save)(**kwargs)
This isn't a replacement for the fully-async serializers — when the serializer does
no I/O the thread hop is pure overhead you might not want — but as an officially
documented escape hatch it gives users a correctness-first option while the async
serializer edge cases get ironed out, and it makes adrf's async CRUD work with any
existing sync serializer unchanged.
Would you take a PR adding something like adrf.serializers.SyncSerializerBridge
(name up to you) plus a docs section on the trade-off?
adrf's async serializers reimplement representation/validation asynchronously, and
several open issues show how hard that surface is to keep correct (#86 — optional
fields silently dropped from
validatein async context; #55, #78 —SynchronousOnlyOperationinato_representationpaths).In production we've had good results with a deliberately smaller approach: keep the
serializers 100% sync DRF (proven code paths — nested serializers, base64 fields,
to_representation,create/updateall unchanged) and bridge only the entrypoints through a thread, which is exactly what
perform_acreate/perform_aupdateneed:
This isn't a replacement for the fully-async serializers — when the serializer does
no I/O the thread hop is pure overhead you might not want — but as an officially
documented escape hatch it gives users a correctness-first option while the async
serializer edge cases get ironed out, and it makes adrf's async CRUD work with any
existing sync serializer unchanged.
Would you take a PR adding something like
adrf.serializers.SyncSerializerBridge(name up to you) plus a docs section on the trade-off?