【问题标题】:Django 1.11 get() missing 1 required positional argument: 'pk'Django 1.11 get() 缺少 1 个必需的位置参数:'pk'
【发布时间】:2019-01-24 11:27:24
【问题描述】:

我使用的是 Django 1.11,但路径参数有问题。 对于所有涉及路径参数的请求,我都会收到这样的错误。

Error:
TypeError at /posts/2
get() missing 1 required positional argument: 'pk'

urls.py
...
url(r'^posts',PostView.as_view()),
url(r'^posts/<int:pk>/',PostView.as_view()),
...

views.py
..
#-------- API for CRUD -----------------#
class PostView(APIView):
    permission_classes = (IsAuthenticated,)

    def get_object(self,pk,user_id):
        try:
            return Post.objects.get(pk=pk,user_id=user_id)
        except Post.DoesNotExist:
            raise Http404

    def get(self,request,pk):
        post = Post.objects.get(user=request.user.id)
        serializer = PostSerializer(post)
        return Response({"success":True,"data":serializer.data},status=status.HTTP_200_OK)

    def put(self, request, pk):
        post = self.get_object(pk,request.user.id)
        serializer = PostSerializer(post, data=request.data)
        if serializer.is_valid():
            serializer.save(user=request.user.id)
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def post(self,request):
        params = request.data
        params['user'] = request.user.id
        serializer = PostSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        saved_data = self.perform_create(serializer)
        post = PostSerializer(saved_data)
        return Response({"success":True, "message":"Post  Added Successfully","data":post.data}, status=status.HTTP_201_CREATED)

    def perform_create(self, serializer):
        return serializer.save()
...

网址示例:

GET : localhost:8000/posts/2

谁能告诉我如何传递位置参数。

【问题讨论】:

  • 你的get方法应该是def get(self, request, pk)
  • 是的,我刚更新忘记把更新的代码放在这里,现在还在工作,我怀疑正则表达式有问题
  • 您是否错过了请求帖子/2 末尾的 / ?
  • @Paras: 现在是在抱怨POST吗?
  • 尝试使用'/'或最后不使用'/',两者都不起作用

标签: python django url django-rest-framework


【解决方案1】:

在上面的代码中,您在请求方法和查看方法get_object 中使用user_idpk 作为位置参数。 pkuser_id 在整个视图中可用。您可以像self.kwargs.get('pk')self.request.user.pk 一样使用它们。 请查看下面的代码了解实现细节。

class PostView(APIView):
    permission_classes = (IsAuthenticated,)

    def get_object(self):
        pk = self.kwargs.get('pk')
        user_id = self.request.id
        try:
           return Post.objects.get(pk=pk,user_id=user_id)
        except Post.DoesNotExist:
           raise Http404

    def get(self,request, *args, **kwargs):
        # ...
        pass

    def put(self, request, *args, **kwargs):
        # ...
        pass

    def post(self,request, *args, **kwargs):
        # ...
        pass

【讨论】:

  • 当我打印这个 print(self.kwargs.get('pk')) 时,我得到 None
  • @Paras 将 url(r'^posts/&lt;int:pk&gt;/',PostView.as_view()), 更改为 url(r'^posts/(?P&lt;pk&gt;\d+)/',PostView.as_view()),。现在,尝试打印print(self.kwargs),您将在self.kwargs 中收到pk
  • 它确实有效,但只有在我删除了这个模式 url(r'^posts',PostView.as_view()) 之后,但我现在得到 404 进行 POST 调用,我该如何处理? CBV 不应该为 HTTP 动词提供封装吗?
  • 无论如何,当我颠倒两个网址的顺序时它确实有效,这意味着现在它们看起来像这样: url(r'^posts/(?P\d+)/',PostView.as_view ()), url(r'^posts',PostView.as_view()),
【解决方案2】:

您的getpost 签名只接受selfrequest 参数,而这里应该包括您的URL 的pk 参数。由于您为 没有 pk 参数的 URL 定义了相同的视图,因此您应该使这些参数 可选 (因此添加一个默认值,以防它们丢失)。喜欢:

class PostView(APIView):
    permission_classes = (IsAuthenticated,)

    def get_object(self,pk,user_id):
        # ...
        pass

    def get(self,request, pk=None):
        # ...
        pass

    def put(self, request, pk=None):
        # ...
        pass

    def post(self,request, pk=None):
        # ...
        pass

另一种方法是在 URL 中提供缺少参数的 kwargs,例如:

path(r'posts',PostView.as_view(), kwargs={'pk': None}),
path(r'posts/<int:pk>/',PostView.as_view())

或者对于 之前的安装,您需要将其定义为正则表达式:

url(r'^posts/$',PostView.as_view(), kwargs={'pk': None}),
url(r'^posts/(?P<pk>[0-9]+)/',PostView.as_view())

【讨论】:

  • 但我需要传递一个 pk 来拨打和接听电话
  • @Paras:你这样做。但请注意,您的 first URL 没有 pk,并且仍然调用 same 视图,因此没有 pk。现在,由于您的 getput 参数需要这样的 pk,我们需要将另一个值传递给它。也许这两个 URL 建模可能是 真正的 问题。构建两个视图可能会更好。
  • 试过了,没用,只有 post 方法有效,put 和 get 方法无效
  • @Paras: 这是有道理的,因为如果你反转 URL,它会选择第一个,因此 URL 丢失,你应该给你的视图不同的名字,并确保 第二个 URL被触发,带有&lt;int:pk&gt;部分。
  • @Paras:等等,你把url(..) 语法和path(..) 语法混在一起。
猜你喜欢
  • 2019-11-12
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 2015-04-06
  • 1970-01-01
  • 2021-12-21
  • 2018-06-20
  • 2017-10-20
相关资源
最近更新 更多