davidteather / TikTok-Api

The Unofficial TikTok API Wrapper In Python
https://davidteather.github.io/TikTok-Api
MIT License
4.77k stars 965 forks source link

[INSTALLATION] - Django SynchronousOnlyOperation Error #840

Closed macmichael01 closed 1 year ago

macmichael01 commented 2 years ago

Describe the error

I have a Django project that I am working on where I am trying to fetch TikTok user info using a class base view.

I am using gunicorn and Django is throwing an error: SynchronousOnlyOperation error. I added this bit of code to my gunicorn wsgi file os.environ.setdefault("DJANGO_ALLOW_ASYNC_UNSAFE", "true") which fixes the problem but seems like a bad idea.

The buggy code

def get_user_info(username):
    verify_fp = "code here"
    try:
        api = TikTokApi(custom_verify_fp=verify_fp)
        user = api.user(username=username)
        info = user.info_full()
        return info
    except Exception:
        return None

class TikTokAccount(APIView):

    def post(self, request, *args, **kwargs):
        ...
        info = get_user_info(username)
        ...

Error Trace (if any)

Put the error trace below if there's any error thrown.

Traceback (most recent call last):
  File "/projects/social-bean/.pyenv/lib/python3.9/site-packages/gevent/pywsgi.py", line 999, in handle_one_response
    self.run_application()
  File "/projects/social-bean/.pyenv/lib/python3.9/site-packages/gevent/pywsgi.py", line 951, in run_application
    close()
  File "/projects/social-bean/.pyenv/lib/python3.9/site-packages/django/http/response.py", line 259, in close
    signals.request_finished.send(sender=self._handler_class)
  File "/projects/social-bean/.pyenv/lib/python3.9/site-packages/django/dispatch/dispatcher.py", line 177, in send
    return [
  File "/projects/social-bean/.pyenv/lib/python3.9/site-packages/django/dispatch/dispatcher.py", line 178, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "/projects/social-bean/.pyenv/lib/python3.9/site-packages/django/db/__init__.py", line 57, in close_old_connections
    conn.close_if_unusable_or_obsolete()
  File "/projects/social-bean/.pyenv/lib/python3.9/site-packages/django/db/backends/base/base.py", line 510, in close_if_unusable_or_obsolete
    if self.get_autocommit() != self.settings_dict['AUTOCOMMIT']:
  File "/projects/social-bean/.pyenv/lib/python3.9/site-packages/django/db/backends/base/base.py", line 389, in get_autocommit
    self.ensure_connection()
  File "/projects/social-bean/.pyenv/lib/python3.9/site-packages/django/utils/asyncio.py", line 24, in inner
    raise SynchronousOnlyOperation(message)
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
2022-02-26T02:14:04Z {'REMOTE_ADDR': '::1', 'REMOTE_PORT': '50871', 'HTTP_HOST': 'localhost:8080', (hidden keys: 27)} failed with SynchronousOnlyOperation

Desktop (please complete the following information):

Walexero commented 2 years ago

From what i can see from the error above. Since you're using WSGI which gunicorn is, then you have to use the django provided method after you have defined the function:

**_

from asgiref.sync import sync_to_async get_user_info = sync_to_async(_get_user_info, thread_sensitive=True)

_**

Else, all you need to do is to upgrade your website sandbox from WSGI to ASGI and make the relevant changes on your django project folder. If you find this helpful reachout on Upwork, my Profile name is Ayanlade Olawale, I saw your post on upwork

davidteather commented 1 year ago

V6 fully async