Hit a classic Django trap this week and figured it's worth sharing since so many people are running into it now.
I was adding an LLM feature to a Django app. The AI call takes a few seconds, so naturally I made the view async so it doesn't block a worker while waiting. Wrote the async view, called the ORM like I always do, and boom:
SynchronousOnlyOperation: You cannot call this from an async context.
Turns out Django's ORM can't just be called normally inside async code. The classic sync API isn't safe in an event loop, so Django protects it and throws this error instead.
The fix is simpler than most people think. Since Django 4.1 the ORM has async versions of everything, same names with an "a" prefix. So objects.get() becomes await objects.aget(), create() becomes acreate(), save() becomes asave(). For loops over querysets, async for works directly. And for old sync code or third party libraries you can't change, wrap them with sync_to_async().
Why this matters right now: everyone is bolting AI features onto Django apps, and LLM calls are exactly the slow I/O that async is made for. Which means a lot of devs who never touched async Django are suddenly hitting this error for the first time.
One honest caveat: transactions still don't fully work in async mode, so if you need atomic blocks, keep that path sync and wrap it.