在django rest框架中保存嵌套的单个对象

时间:2015-02-09 08:00:07

标签: django django-rest-framework

我有3个对象 - Company,Expert和RecentProject,其中RecentProject具有ForeignKey to Company和ManyToMany与专家的关系:

class RecentProject(BaseProfileObject):
    company = models.ForeignKey(
        'experts.Company',
        verbose_name=_("Company"),
        blank=True,
        null=True,
        related_name='projects')
    experts = models.ManyToManyField(
        "Expert",
        verbose_name=_("Experts"),
        blank=True,
        null=True,
        related_name='projects')
    class Meta:
        verbose_name = _("Recent project")
        verbose_name_plural = _("Recent projects")

我想要的是能够从端点发布新的近期项目,如

api / v1 / companies / 1 / recentprojects /和api / v1 / experts / 1 / recentprojects /

在第一种情况下,如果用户可以对公司进行更改,则seralizer应该能够验证(或者更确切地进行权限检查),如果用户可以对专家进行更改,则可以进行第二种情况。 我似乎无法找到的是如何让权限知道父对象的例子(第一种情况下的公司和第二种情况下的专家)。

我知道可以使用权限来完成,所以我创建了以下权限:

class UserCanModifyCompany(permissions.BasePermission):
    def has_permission(self, request, view):
        # Do check here
        return False

我将它添加到我的视图中: class RecentProjectViewSet(viewsets.ModelViewSet):     queryset = RecentProject.objects.all()     serializer_class = RecentProjectSerializer

@permission_classes((UserIsAuthenticatedExpert, UserCanModifyCompany))
def create(self, request, *args, **kwargs):
    return super(RecentProjectViewSet, self).create(request, *args, **kwargs)

@permission_classes((UserIsAuthenticatedExpert, UserCanModifyCompany))
def update(self, request, *args, **kwargs):
    return super(RecentProjectViewSet, self).update(request, *args, **kwargs)

但是我怎样才能确保权限检查有可用于公司/专家访问检查的信息。或者我是否需要为公司/专家最近的项目保存创建不同的视图集,并为这两个项目设置不同的权限类别?

1 个答案:

答案 0 :(得分:2)

首先,为同一资源创建两个不同的端点并不是一个好主意。我建议你使用单一端点:api/v1/recentprojects/。 话虽如此,我一直处于类似情况,我认为您最好的选择是在 公司和专家视图集 上使用@detail_route。 例如,在ExpertViewSet

@detail_route(methods=['post'], , permission_classes=[UserIsAuthenticatedExpert, UserCanModifyCompany])
    def recentprojects(self, request, pk=None):
        expert = self.get_object()
        serializer = RecentProjectSerializer(data=request.data)
        if serializer.is_valid():
            recent_project = serializer.save(company=somecompany)
            recent_project.experts.add(expert)
            return Response({'status': 'ok'})
        else:
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

这样您就可以将新的最新项目发布到api/v1/experts/{pk}/recentprojects/。 至于权限,您需要实现has_object_permission,因为这是一个单一的对象端点:

class UserIsAuthenticatedExpert(permissions.BasePermission):

    def has_object_permission(self, request, view, obj):
        return some_condition

您还可以与get_queryset一起覆盖self.action以过滤端点可以操作的专家或公司实例,但这会引发404错误而不是403错误。