Django - DRF 删除/检索/补丁返回 404 详细信息:“未找到”

Posted

技术标签:

【中文标题】Django - DRF 删除/检索/补丁返回 404 详细信息:“未找到”【英文标题】:Django - DRF Delete/Retrieve/Patch Returns 404 detail: "Not found" Django - DRF 删除/检索/补丁返回 404 详细信息:“未找到” 【发布时间】:2018-08-26 03:02:03 【问题描述】:

经过大约 4-5 小时的密集调试。 我放弃了寻找导致这种情况的原因,可能非常简单,错误。 使用 Update 和 Patch/Put Mixins 进行了尝试,但效果不佳。 由于查询集,它是 100%,但我找不到问题? 尝试使用 .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])

附:该查询集与 ListModelMixin 完美配合。我读到 List 用于集合,而 Retrieve/Destroy/Update 用于单个模型实例,但是如何让查询集成为单个模型实例?我在任何地方都找不到

编辑:添加与问题相关的序列化程序和模型 sn-ps

序列化器:

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()

【问题讨论】:

你的类定义没有正确缩进。请更正问题中的代码,使其成为有效的 Python 语法。 在嵌套的 enpoints 中表示 m2m 关系可能会导致非常深的嵌套和笨拙的 api。使用查询过滤更干净。 /api/v1/model3d/?owner=20. 您确定self.kwargs["pk"] 是用户pk 的详细视图、删除视图和补丁视图吗?默认为 serializer_class 使用pk。如果你想要嵌套路由,有可用的插件。 chibisov.github.io/drf-extensions/docs/#nested-routes 或 github.com/alanjds/drf-nested-routers 是的,我确信 get_queryset 中的查询返回的正是我想要的。只是 .destroy .update .partitial_update 方法不喜欢它,返回 404。 .list 方法工作得很好,可能是因为查询集是一个集合/数组,不确定。 【参考方案1】:

GenericApiView 的默认lookup_url_kwargpk。但是您使用它来过滤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_object 方法由 retrieve() (GET) update() PATCH/PUT 和 destroy() (DELETE) 使用,默认使用 self.kwargs['pk'] 作为查找值。

【讨论】:

你是金子!!非常感谢!

以上是关于Django - DRF 删除/检索/补丁返回 404 详细信息:“未找到”的主要内容,如果未能解决你的问题,请参考以下文章

如何在 django(DRF)中检索对象列表(包括 ForeignKey 字段数据)而不显着增加数据库调用时间

Django/DRF - 405 方法不允许删除操作

Django(42)DRF安装与使用

DRF 总是返回“未提供身份验证凭据”

drf django rest auth 如何过期或删除令牌?

Django DRF序列化器或视图中的多表过滤