代码之家  ›  专栏  ›  技术社区  ›  Viktor Velev

Django-DRF Delete/Retrieve/Patch返回404{详细信息:“未找到”}

  •  4
  • Viktor Velev  · 技术社区  · 6 年前

    经过约4-5小时的密集调试。 我放弃了寻找导致这个错误的原因,可能真的很简单,bug。 用Update和Patch/Put Mixin尝试了这一点,但效果不佳。 这完全是因为queryset,但我找不到问题? 已尝试使用。get()和我能想到的所有其他内容。

    我的观点很直截了当:

    class RemoveModel3D(generics.DestroyAPIView):
    
        serializer_class = Model3DSerializer
    
        def get_queryset(self):
            user_pk = self.kwargs["pk"]
            return Model3D.objects.filter(owners__in=[user_pk])
    

    P、 该queryset在ListModelMixin中工作得非常好。我读到这个列表是针对集合的,而检索/销毁/更新是针对单个模型实例的,但是我如何将queryset设置为单个模型实例呢?我到处都找不到

    编辑:添加与问题相关的序列化程序和模型片段

    序列化程序:

    class Model3DSerializer(serializers.ModelSerializer):
    
        User = get_user_model()
    
        commits = CommitSerializer(many=True, required=False, read_only=True)
        favorited_by = UserSerializer(many=True, required=False, read_only=True)
    
        date_uploaded = serializers.DateTimeField(read_only=True)
        owners = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    
        class Meta:
            model = Model3D
            fields = (
                'id',
                'title',
                'owners',
                'description',
                'date_uploaded',
                'favorited_by',
                'commits'
            )
    

    型号:

    class Model3D(models.Model):
    
        title = models.CharField(max_length=64)
        # Many models many owners, seems reasonable to me
        owners = models.ManyToManyField(User, related_name='owners')
        description = models.TextField(null=True)
        date_uploaded = models.DateTimeField(auto_now_add=True)
    
        # Many models many people who like them.
        favorited_by = models.ManyToManyField(User, related_name='favorited_by')
    

    视图:

    class ListAllModels3D(generics.ListAPIView):
    
        serializer_class = Model3DSerializer
    
        def get_queryset(self):
            queryset = Model3D.objects.all()
            model_id = self.request.query_params.get('id', None)
    
            if model_id is not None:
                queryset = queryset.filter(pk=model_id)
    
            return queryset
    
    class RemoveModel3D(generics.DestroyAPIView):
    
        serializer_class = Model3DSerializer
    
        def get_queryset(self):
            queryset = Model3D.objects.all()
            model_id = self.request.query_params.get('id', None)
    
            if model_id is not None:
                queryset = queryset.filter(pk=model_id)
    
            return queryset
    
    
    class Models3D( mixins.ListModelMixin,
                mixins.CreateModelMixin,
                generics.GenericAPIView,
            ):
    
        serializer_class = Model3DSerializer
    
        def get_queryset(self):
            user_pk = self.kwargs["pk"]
            return Model3D.objects.filter(owners__in=[user_pk])
    
        def get(self, request, *args, **kwargs):
            return self.list(request, *args, **kwargs)
    
        def post(self, request, *args, **kwargs):
            return self.create(request, *args, **kwargs)
    
        def perform_create(self, serializer):
            # FIXME: this is a bad way to set the value, but ...
            user_id = self.kwargs["pk"]
            serializer.validated_data['owners'] = [user_id]
    
            serializer.save()
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   Håken Lid    4 年前

    默认值 lookup_url_kwarg 对于GenericApiView是 pk 。但你用它来过滤 User ,因此在查询Owner和Model3D时将使用相同的pk值。

    结果类似于此伪代码,除非用户和model3d具有相同的pk,否则将导致404响应。

    kwargs = {'pk': 20} 
    try:
       Model3D.objects.get(owners__in=[kwargs['pk']], pk=kwargs['pk'])
    except ObjectNotFound:
       raise Http404Exception('Not found')
    

    要解决这个问题,可以使用支持嵌套api路由的插件。或者可以覆盖视图集 get_object 方法,这是引发404的地方。

    def get_object(self):
        queryset = self.get_queryset()
        pk = self.request.query_params.get('id', None)
        obj = get_object_or_404(queryset, pk=pk)
        self.check_object_permissions(self.request, obj)
        return obj
    

    http://www.django-rest-framework.org/api-guide/generic-views/#get_objectself

    这个 get\u对象 方法由使用 retrieve() (获取) update() 修补/放置和 destroy() (删除),默认为使用 self.kwargs['pk'] 作为查找值。