49

Django 3.0 is adding asgi / async support and with it a guard around making synchronous requests in an async context. Concurrently, IPython just added top level async/await support, which seems to be running the whole interpreter session inside of a default event loop.

Unfortunately the combination of these two great addition means that any django ORM operation in a jupyter notebook causes a SynchronousOnlyOperation exception:

SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.

As the exception message says, it's possible to wrap each ORM call in a sync_to_async() like:

images = await sync_to_async(Image.objects.all)()

but it's not very convenient, especially for related fields which would usually be implicitly resolved on attribute lookup.

(I tried %autoawait off magic but it didn't work, from a quick glance at the docs I'm assuming it's because ipykernels always run in an asyncio loop)

So is there a way to either disable the sync in async context check in django or run an ipykernel in a synchronous context?


For context: I wrote a data science package that uses django as a backend server but also exposes a jupyter based interface on top of the ORM that allows you to clean/annotate data, track machine learning experiments and run training jobs all in a jupyter notebook.

michalwols
  • 648
  • 1
  • 5
  • 8

4 Answers4

53

It works for me

os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"

BTW, I start my notebook using the command

./manage.py shell_plus --notebook
Rob Bednark
  • 25,981
  • 23
  • 80
  • 125
Wojtas Koziej
  • 631
  • 4
  • 4
  • I have tried this. it still shows the error in jupyter. Where should i put `os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"`. I tried inside jupyter and also added to settings.py. BUt still my jupyter is giving error – Santhosh Feb 01 '20 at 09:11
  • 4
    I put it in notebook – Wojtas Koziej Feb 05 '20 at 18:29
  • @SanthoshYedidi do it in the cli. Export the variable before running the jupyter server. – Siddharth Pant Apr 09 '20 at 23:53
  • 1
    worked for me too. just add it to the settings.py and run shell_plus on notebook – Shekhar Apr 16 '20 at 14:20
  • 3
    This solution was not giving me results until I updated Django from 3.0.0 to 3.0.6. – dmmfll May 06 '20 at 17:01
  • Thanks, I am on Django 3.0.10 and Python 3.7.8 - Actually just today upgraded from Django 2.0 to Django 3.0 and observed this issue while using ipython 7.18.1 with jupyter notebook. Added `export DJANGO_ALLOW_ASYNC_UNSAFE='true'` to my shell startup file and it now works like a charm :) – Deep Sep 23 '20 at 09:21
  • 1
    @dmmfll, I was at 3.0 and it was not working at all. then saw you comment, upgraded to 3.0.6 and now it works, thanks – Santhosh Dec 19 '20 at 19:10
10

Contrary to other answers I'd suggest just running from the shell as:

env DJANGO_ALLOW_ASYNC_UNSAFE=true ./manage.py shell_plus --notebook

and not modifying any config files or startup scripts.

The advantage of doing it like this is that these checks still seem useful to have enabled almost everywhere else (e.g. when debugging locally via runserver or when running tests). Disabling via files would easily disable these in too many places negating their advantage.

Note that most shells provide easy ways of recalling previously invoked command lines, e.g. in Bash or Zsh Ctrl+R followed by notebook would find the last time you ran something that had "notebook" in. Under the fish shell just type notebook and press the up arrow key to start a reverse search.

Sam Mason
  • 15,216
  • 1
  • 41
  • 60
5

For now I plan on just using a forked version of django with a new setting to skip the async_unsafe check. Once the ORM gets async support I'll probably have to rewrite my project to support it and drop the flag.

EDIT: there's now a PR to add an env variable (DJANGO_ALLOW_ASYNC_UNSAFE) to disable the check (https://github.com/django/django/pull/12172)

michalwols
  • 648
  • 1
  • 5
  • 8
  • 2
    This change is now scheduled for [3.0.1](https://docs.djangoproject.com/en/3.0/releases/3.0.1/) – Sayse Dec 12 '19 at 20:15
1

I added

os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true" code in the setting.py of your project all the way down to the file and then

command python3 manage.py shell_plus --notebook

if you are using python3 or use python

That's it. worked for me.

Shashikant Pandit
  • 2,752
  • 22
  • 29