Hello folks,
I’m having a problem and running out of options. I have an app that I’ve decided to make asynchronous. In this app I have several models and several helper functions that make the ORM queries. In my view I call those functions and create a dashboard for the user.
Since the ORM is synchronous, I decorated those functions with the Django Channels database_sync_to_async decorator. For most of them it works perfectly, but for the two functions that query one specific model (Transaction) it doesn’t work.
Here’s a part of my view:
async def dashboard_view(request):
# rest of the code ommited
(balance, transactions, accounts, categories,
installments) = await asyncio.gather(*[
functions.get_group_balance(request.user, month), # all these functions have the decorator
functions.get_group_actual_transactions(request.user, month), # the ones that query the Transaction model don't work
functions.get_group_accounts(request.user, month),
functions.get_group_categories(request.user, month),
functions.get_group_installments(request.user, month) # this one too
])
return render(
request,
"transaction/dashboard.html",
{
"balance": balance, "transactions": transactions,
"accounts": accounts, "month": month, "categories": categories,
"installments": installments, "next_month": next_month,
"previous_month": previous_month
}
)
The helper function:
@database_sync_to_async
def get_group_actual_transactions(user, month):
group_transactions = # code ommited, but it's a filtered Queryset from a related model
group_transactions.total_income = group_transactions.filter(
type='income').aggregate(Sum('amount'))['amount__sum'] or Decimal(0)
group_transactions.total_expense = group_transactions.filter(
type='expense').aggregate(Sum('amount'))['amount__sum'] or Decimal(0)
group_transactions.total_credit_card = group_transactions.filter(
type='invoice_payment'
).aggregate(Sum('amount'))['amount__sum'] or Decimal(0)
group_transactions.total_savings = group_transactions.filter(
type='savings').aggregate(Sum('amount'))['amount__sum'] or Decimal(0)
group_transactions.total_withdrawal = group_transactions.filter(
type='withdrawal'
).aggregate(Sum('amount'))['amount__sum'] or Decimal(0)
return group_transactions
Template:
{% for transaction in transactions|dictsortreversed:"date"|slice:5 %} # this line raises the error. I've tried removing the filter, thinking it's not compatible with async but it didn't work either
{% for transaction in installment.upcoming_transactions %} # if I comment the other part, then this one raises the error
Error:
SynchronousOnlyOperation at /dashboard
You cannot call this from an async context - use a thread or sync_to_async.
Looking at the traceback, it seems to be raised when the database is queried, but IMO it should work fine because of the database_sync_to_async decorator. And it’s also a mistery why it works with all other functions but not with these two. Most of them return Querysets that I iter through in the template.
I tried commenting out the custom manager for this model and it didn’t work either, whereas other models also have custom managers.
Please help!