通过WebSocket更新数据库数据时遇参数错误问题求助
问题
通过WebSocket连接时更新数据库中用户的连接时间戳,触发如下错误:
Exception inside application: __init__() takes 1 positional argument but 2 were given Traceback (most recent call last): File "C:\Users\15512\anaconda3\lib\site-packages\channels\staticfiles.py", line 44, in __call__ return await self.application(scope, receive, send) File "C:\Users\15512\anaconda3\lib\site-packages\channels\routing.py", line 71, in __call__ return await application(scope, receive, send) File "C:\Users\15512\anaconda3\lib\site-packages\channels\security\websocket.py", line 37, in __call__ return await self.application(scope, receive, send) File "C:\Users\15512\Desktop\django-project\peerplatform\signup\middleware.py", line 47, in __call__ return await super().__call__(scope, receive, send) File "C:\Users\15512\anaconda3\lib\site-packages\channels\middleware.py", line 26, in __call__ return await self.inner(scope, receive, send) File "C:\Users\15512\anaconda3\lib\site-packages\channels\sessions.py", line 47, in __call__ return await self.inner(dict(scope, cookies=cookies), receive, send) File "C:\Users\15512\anaconda3\lib\site-packages\channels\sessions.py", line 263, in __call__ return await self.inner(wrapper.scope, receive, wrapper.send) File "C:\Users\15512\anaconda3\lib\site-packages\channels\auth.py", line 185, in __call__ return await super().__call__(scope, receive, send) File "C:\Users\15512\anaconda3\lib\site-packages\channels\middleware.py", line 26, in __call__ return await self.inner(scope, receive, send) File "C:\Users\15512\anaconda3\lib\site-packages\channels\routing.py", line 150, in __call__ return await application( File "C:\Users\15512\anaconda3\lib\site-packages\channels\consumer.py", line 94, in app return await consumer(scope, receive, send) File "C:\Users\15512\anaconda3\lib\site-packages\channels\consumer.py", line 58, in __call__ await await_many_dispatch( File "C:\Users\15512\anaconda3\lib\site-packages\channels\utils.py", line 51, in await_many_dispatch await dispatch(result) File "C:\Users\15512\anaconda3\lib\site-packages\channels\consumer.py", line 73, in dispatch await handler(message) File "C:\Users\15512\Desktop\django-project\peerplatform\signup\consumers.py", line 34, in websocket_connect result = (await self.update_timestamp(group_name)) File "C:\Users\15512\anaconda3\lib\site-packages\asgiref\sync.py", line 414, in __call__ ret = await asyncio.wait_for(future, timeout=None) File "C:\Users\15512\anaconda3\lib\asyncio\tasks.py", line 455, in wait_for return await fut File "C:\Users\15512\anaconda3\lib\concurrent\futures\thread.py", line 57, in run result = self.fn(*self.args, **self.kwargs) File "C:\Users\15512\anaconda3\lib\site-packages\channels\db.py", line 13, in thread_handler return super().thread_handler(loop, *args, **kwargs) File "C:\Users\15512\anaconda3\lib\site-packages\asgiref\sync.py", line 455, in thread_handler return func(*args, **kwargs) File "C:\Users\15512\Desktop\django-project\peerplatform\signup\consumers.py", line 108, in update_timestamp serializer_class = UpdateProfileView(request) TypeError: __init__() takes 1 positional argument but 2 were given
相关代码:
consumers.py 中的 WebSocket 处理逻辑
class PracticeConsumer(AsyncWebsocketConsumer): async def websocket_connect(self, event): ... group_name = username_id result = (await self.update_timestamp(group_name)) await self.channel_layer.group_add( '{}'.format(group_name), self.channel_name ) await self.accept() ... @database_sync_to_async def update_timestamp(self, user_id): time = timezone.now().isoformat() request = dict({'method': 'PUT', 'connected_timestamp': time, 'user.id': self.user_id}) serializer_class = UpdateProfileView(request) return User.objects.filter(user__id=user_id).values()
UpdateProfileView 实现
class UpdateProfileView(generics.UpdateAPIView): queryset = User.objects.all() serializer_class = UpdateUserSerializer def profile(self, request): if request.method == 'PUT': try: user = User.objects.get(id=request.user.id) serializer_user = UpdateUserSerializer(user, many=True) if serializer_user.is_valid(): serializer_user.save() return Response(serializer_user) except User.DoesNotExist: return Response(data='no such user!', status=status.HTTP_400_BAD_REQUEST)
错误原因
- APIView 实例化方式错误:
UpdateProfileView是 Django REST Framework 的generics.UpdateAPIView子类,这类视图不能直接通过UpdateProfileView(request)实例化。DRF 视图的构造函数需要接收request、*args、**kwargs等参数,且通常由 Django 的路由系统自动处理实例化,而非手动调用。 - 视图方法定义错误:DRF 的更新视图应该实现
put方法,而非自定义的profile方法,否则框架无法识别并调用该逻辑。 - 冗余的视图调用:在 WebSocket Consumer 中直接调用 APIView 完全没必要,直接操作模型或复用序列化逻辑即可完成更新,绕路调用视图反而增加复杂度。
修复方案
方案一:直接在 Consumer 中更新数据库(最简方案)
修改 consumers.py 中的 update_timestamp 方法,跳过 APIView,直接更新用户模型:
@database_sync_to_async def update_timestamp(self, user_id): time = timezone.now().isoformat() # 直接更新用户的 connected_timestamp 字段 updated_count = User.objects.filter(id=user_id).update(connected_timestamp=time) # 返回更新后的用户数据(如果需要) return User.objects.filter(id=user_id).values() if updated_count > 0 else None
方案二:复用序列化逻辑(若需验证数据)
如果需要复用 UpdateUserSerializer 的验证逻辑,可单独抽离更新函数,避免调用 APIView:
- 在
views.py中抽离更新逻辑:
def update_user_timestamp(user_id, timestamp): try: user = User.objects.get(id=user_id) serializer = UpdateUserSerializer(user, data={'connected_timestamp': timestamp}, partial=True) if serializer.is_valid(): serializer.save() return serializer.data return None except User.DoesNotExist: return None
- 在 Consumer 中调用该函数:
@database_sync_to_async def update_timestamp(self, user_id): time = timezone.now().isoformat() return update_user_timestamp(user_id, time)
修正 UpdateProfileView(若需保留 API 功能)
如果 UpdateProfileView 仍需作为 API 接口使用,需修正视图方法:
class UpdateProfileView(generics.UpdateAPIView): queryset = User.objects.all() serializer_class = UpdateUserSerializer permission_classes = [IsAuthenticated] # 需添加权限验证确保用户只能修改自己的信息 def put(self, request, *args, **kwargs): # 若要限定用户只能修改自己的信息,可覆盖 get_object 方法 return self.update(request, *args, **kwargs) def get_object(self): # 确保用户只能获取并修改自己的信息 return self.request.user
内容的提问来源于stack exchange,提问作者Emm
相关产品推荐
相关产品推荐

