You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨Django应用关联URL触发get()意外user_id关键字参数错误如何解决

问题排查与解决方案

错误核心原因

  1. 参数名不匹配:你将studio应用的路由嵌套在accounts/<uuid:user_id>/路径下,所有studio的视图函数都会自动收到user_id参数,但你studio的多个视图中参数名写的是u_id,和传入的user_id名称不一致,就会抛出get() got an unexpected keyword argument 'user_id'错误。
  2. 路由匹配冲突:accounts的urls.py中,accounts/<uuid:user_id>/路径同时匹配用户详情接口和studio路由,Django按顺序匹配会优先进入用户详情接口,永远不会走到studio路由。
  3. ORM使用错误:查询多条数据时用了.get()方法,.get()只能返回单条对象,后续切片操作会直接报错。

修复步骤

1. 调整accounts/urls.py路由顺序和前缀

避免路由冲突,给studio路由加专属前缀:

from django.urls import path, include

from . import views

urlpatterns = [
    path(r'accounts/', views.CustomUserListView.as_view()),
    # 把studio路由放前面,加/studio/前缀避免冲突
    path(r'accounts/<uuid:user_id>/studio/', include('studio.urls')),
    path(r'accounts/<uuid:user_id>/',
         views.CustomUserDetailView.as_view(), name='my-account'),
]

2. 统一studio/views.py的参数名,修正ORM查询

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

from django.http.response import Http404

from .models import Session, LaserData
from .serializers import SessionSerializer, LaserDataSerializer


class SessionListView(APIView):
    # 参数名改为user_id和传入参数一致
    def get(self,  request, user_id, format=None):
        # 用filter查询多条数据,替换get
        session = Session.objects.filter(user_id=user_id)[:9]
        serializer = SessionSerializer(session, many=True)
        return Response(serializer.data)

    # post方法也要接收user_id,创建时自动关联用户
    def post(self, request, user_id):
        serializer = SessionSerializer(data=request.data)
        if serializer.is_valid():
            # 保存时关联当前用户,不用前端传user_id
            serializer.save(user_id_id=user_id)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class SessionDetailView(APIView):
    def get_session(self, u_id, s_id):
        try:
            return Session.objects.filter(user_id=u_id).get(session_id=s_id)
        except Session.DoesNotExist:
            raise Http404

    def get(self, request, user_id, session_id, format=None):
        session = self.get_session(user_id, session_id)
        serializer = SessionSerializer(session)
        return Response(serializer.data)


class LaserDataListView(APIView):
    # 参数名改为user_id、session_id和传入参数一致
    def get(self,  request, user_id, session_id, format=None):
        # 用filter查询多条数据,替换get
        laser_data = LaserData.objects.filter(
            user_id=user_id, session_id=session_id)[:9]
        serializer = LaserDataSerializer(laser_data, many=True)
        return Response(serializer.data)

    # post方法接收user_id、session_id,自动关联
    def post(self, request, user_id, session_id):
        serializer = LaserDataSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(user_id_id=user_id, session_id_id=session_id)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class LaserDatumDetailView(APIView):
    def get_datum(self, u_id, s_id, time):
        try:
            return LaserData.objects.get(
                user_id=u_id,
                session_id=s_id,
                timestamp=time
            )
        except LaserData.DoesNotExist:
            raise Http404

    def get(self, request, user_id, session_id, timestamp, format=None):
        laser_datum = self.get_datum(user_id, session_id, timestamp)
        serializer = LaserDataSerializer(laser_datum)
        return Response(serializer.data)

3. (可选优化)修正模型字段命名避免混淆

你现在的外键字段名加了_id后缀,Django会自动给外键字段在数据库中加_id后缀,导致最终数据库字段变成user_id_id,非常容易混淆,建议修改模型字段:

# studio/models.py
class Session(models.Model):
    # 把user_id改为user,外键名不要带_id后缀
    user = models.ForeignKey(
        'accounts.CustomUser', on_delete=models.CASCADE)
    session_id = models.CharField(max_length=100, unique=True, blank=False)

class LaserData(models.Model):
    user = models.ForeignKey(
        'accounts.CustomUser', on_delete=models.CASCADE)
    # 把session_id改为session
    session = models.ForeignKey('Session', on_delete=models.CASCADE)
    # 其余字段不变

修改后视图中保存的代码也要对应调整:

# SessionListView.post中改为
serializer.save(user_id=user_id)
# LaserDataListView.post中改为
serializer.save(user_id=user_id, session_id=session_id)

开发最佳实践建议

  • 权限控制:给所有需要登录的接口加上permission_classes = [IsAuthenticated]校验,同时增加逻辑确保用户只能操作自己的数据,避免越权访问。
  • 复用通用视图:DRF提供了ListCreateAPIView、RetrieveUpdateDestroyAPIView等通用视图,不用手动写get/post等方法,减少重复代码。
  • 分页处理:列表查询不要硬编码取前N条,用DRF自带的分页组件,支持前端传页码、每页数量参数。
  • 输入校验:时间戳参数从URL传入时是字符串,要增加格式校验转成datetime类型再查询,避免匹配失败。
  • 序列化器拆分:针对不同的接口(新增、查询、更新)可以拆分不同的序列化器,避免暴露不必要的字段给前端。

内容的提问来源于stack exchange,提问作者Denis Nakazawa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 20:18:04