Django Async View with ORM and thread_sensitive=False

Is it fundamentally wrong to use an async view with thread_sensitive=False performing an Django ORM call?

For instance:

def call_to_a_3rd_party_API():
	something = requests.post(...)
	return something

@sync_to_async(thread_sensitive=False)
def do_something_to_a_product(request, id):
    product = Product.objects.get(pk=id)
    result = call_to_a_3rd_party_API()
    product.some_value = result
    product.update()    ​
    ​return HttpResponse(status=200)

The goal here is that I am migrating some of my Django 2.2 views due to blocking IO behaviour (from calling 3rd party APIs) to Django 3.1 async views. In my tests, the only way I could turn the 3rd party API call in non-blocking is using thread_sensitive=False.

Reading the docs (Asynchronous support | Django documentation | Django) it feels like we should never use thread_sensitive=False with Django ORM. So the alternative I guessed would be:

@sync_to_async(thread_sensitive=False)
def call_to_a_3rd_party_API():
	something = requests.post(...)
	return something

async def do_something_to_a_product(request, id):
    product = await sync_to_async(Product.objects.get, thread_sensitive=True)(Product, pk=id)
    result = await call_to_a_3rd_party_API()
    product.some_value = result
    await sync_to_async(product.save, thread_sensitive=True)
   ​return HttpResponse(status=200)

It feels like this way I can turn the call_to_a_3rd_party_API() into a non-blocking function, while keeping all the Django ORM in the main thread. But the code feels a lot more complex.

Could someone help me with this?

Extra question: I have two projects, one of them using wsgi and the other asgi. Does it make a difference regarding the issue above?

I think I’d try to write this like the following:

@sync_to_async
async def update_product(id, result):
    product = Product.objects.get(pk=id)
    product.some_value = result
    product.save()

async def do_something_to_a_product(request, id):
    result = await call_to_a_3rd_party_API()
    await update_product(id, result)
   ​return HttpResponse(status=200)

The case in which your approach would be required is if you want to validate that the instance exists before hitting the 3rd party API.

1 Like

Hey Tim, indeed that is a good suggestion of code. Regarding the thread_sensitiveness of Django ORM, should I always keep it True?

I haven’t dug into this myself, but I would utilize the defaults until I found a reason why they won’t work. Also, I’m not sure if you’re using Django Channels, but there’s some good information there. If you’re not, you should probably consider making your own version of database_sync_to_async from channels/db.py at main · django/channels · GitHub

Thanks a lot! I will look into It. Yes, I am using channels with gunicorn+uvicorn. Thanks Tim!