问题描述
我使用的是 Python 3.7、Django 3.1.7、social-auth-app-django 3.1.0。
我刚刚开始玩异步视图。我不能让他们用 LoginrequiredMixin 玩得很好。我有这个微不足道的看法:
class TestView(LoginrequiredMixin,View):
@classonlymethod
def as_view(cls,**initkwargs):
view = super().as_view(**initkwargs)
view._is_coroutine = asyncio.coroutines._is_coroutine
return view
async def get(self,request):
return render(request,'spi/test.jinja',{})
当我运行这个测试时:
class TestViewTest(ViewTestCase):
def test_get(self):
client = Client()
response = client.get('/spi/test')
self.assertEqual(response.status_code,200)
它以令人敬畏的堆栈转储失败(如下),其要点是:
TypeError: object HttpResponseRedirect can't be used in 'await' expression
我认为这是由于正在运行的 OAuth 流程。如果我省略 LoginrequiredMixin,则测试通过。
--- Logging error ---
Traceback (most recent call last):
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/handlers/exception.py",line 47,in inner
response = get_response(request)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/handlers/base.py",line 181,in _get_response
response = wrapped_callback(request,*callback_args,**callback_kwargs)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/asgiref/sync.py",line 147,in __call__
return call_result.result()
File "/data/project/spi-tools-dev/python-distros/python-3.7.3-install/lib/python3.7/concurrent/futures/_base.py",line 425,in result
return self.__get_result()
File "/data/project/spi-tools-dev/python-distros/python-3.7.3-install/lib/python3.7/concurrent/futures/_base.py",line 384,in __get_result
raise self._exception
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/asgiref/sync.py",line 212,in main_wrap
result = await self.awaitable(*args,**kwargs)
TypeError: object HttpResponseRedirect can't be used in 'await' expression
During handling of the above exception,another exception occurred:
Traceback (most recent call last):
File "/data/project/spi-tools-dev/python-distros/python-3.7.3-install/lib/python3.7/logging/handlers.py",line 630,in emit
s = self.makePickle(record)
File "/data/project/spi-tools-dev/python-distros/python-3.7.3-install/lib/python3.7/logging/handlers.py",line 602,in makePickle
s = pickle.dumps(d,1)
File "/data/project/spi-tools-dev/python-distros/python-3.7.3-install/lib/python3.7/copyreg.py",line 65,in _reduce_ex
raise TypeError("can't pickle %s objects" % base.__name__)
TypeError: can't pickle BytesIO objects
Call stack:
File "/data/project/spi-tools-dev/www/python/src/manage.py",line 25,in <module>
main()
File "/data/project/spi-tools-dev/www/python/src/manage.py",line 21,in main
execute_from_command_line(sys.argv)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/management/__init__.py",line 401,in execute_from_command_line
utility.execute()
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/management/__init__.py",line 395,in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/management/commands/test.py",line 23,in run_from_argv
super().run_from_argv(argv)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/management/base.py",line 330,in run_from_argv
self.execute(*args,**cmd_options)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/management/base.py",line 371,in execute
output = self.handle(*args,**options)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/management/commands/test.py",line 53,in handle
failures = test_runner.run_tests(test_labels)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/test/runner.py",line 699,in run_tests
result = self.run_suite(suite)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/test/runner.py",line 641,in run_suite
return runner.run(suite)
File "/data/project/spi-tools-dev/python-distros/python-3.7.3-install/lib/python3.7/unittest/runner.py",line 176,in run
test(result)
File "/data/project/spi-tools-dev/python-distros/python-3.7.3-install/lib/python3.7/unittest/suite.py",line 84,in __call__
return self.run(*args,**kwds)
File "/data/project/spi-tools-dev/python-distros/python-3.7.3-install/lib/python3.7/unittest/suite.py",line 122,in run
test(result)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/test/testcases.py",line 243,in __call__
self._setup_and_call(result)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/test/testcases.py",line 279,in _setup_and_call
super().__call__(result)
File "/data/project/spi-tools-dev/python-distros/python-3.7.3-install/lib/python3.7/unittest/case.py",line 663,**kwds)
File "/data/project/spi-tools-dev/python-distros/python-3.7.3-install/lib/python3.7/unittest/case.py",line 615,in run
testMethod()
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/src/spi/test_views.py",line 231,in test_get
response = client.get('/spi/test')
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/test/client.py",line 739,in get
response = super().get(path,data=data,secure=secure,**extra)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/test/client.py",in get
**extra,File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/test/client.py",line 470,in generic
return self.request(**r)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/test/client.py",line 711,in request
response = self.handler(environ)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/test/client.py",line 142,in __call__
response = self.get_response(request)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/handlers/base.py",line 130,in get_response
response = self._middleware_chain(request)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/handlers/exception.py",in inner
response = get_response(request)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/utils/deprecation.py",line 114,in __call__
response = response or self.get_response(request)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/handlers/exception.py",in inner
response = get_response(request)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/debug_toolbar/middleware.py",line 52,in __call__
return self.get_response(request)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/handlers/exception.py",in inner
response = get_response(request)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/src/tools_app/middleware.py",line 26,line 11,line 49,in inner
response = response_for_exception(request,exc)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/handlers/exception.py",line 108,in response_for_exception
exc_info=sys.exc_info(),File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/utils/log.py",line 230,in log_response
exc_info=exc_info,Message: '%s: %s'
Arguments: ('Internal Server Error','/spi/test')
E
======================================================================
ERROR: test_get (spi.test_views.TestViewTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/src/spi/test_views.py",line 716,in request
self.check_exception(response)
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/test/client.py",line 577,in check_exception
raise exc_value
File "/mnt/nfs/labstore-secondary-tools-project/spi-tools-dev/www/python/venv/lib/python3.7/site-packages/django/core/handlers/exception.py",**kwargs)
TypeError: object HttpResponseRedirect can't be used in 'await' expression
----------------------------------------------------------------------
Ran 1 test in 0.274s
Failed (errors=1)
Destroying test database for alias 'default'...
解决方法
好吧,事实证明问题很简单,LoginRequiredMixin 还不能异步。解决方法是在我的视图代码中实现 LoginRequiredMixin 的要点。 supplied implementation of LoginRequiredMixin 很复杂,但大部分是处理一般情况。将其分解为适合我的用例的基本部分,我最终得到:
from asgiref.sync import sync_to_async
from django.contrib.auth.views import redirect_to_login
class TestView(View):
@classonlymethod
def as_view(cls,**initkwargs):
view = super().as_view(**initkwargs)
view._is_coroutine = asyncio.coroutines._is_coroutine
return view
async def get(self,request):
if not await sync_to_async(lambda: request.user.is_authenticated)():
return redirect_to_login(self.request.get_full_path())
return render(request,'spi/test.jinja',{})