如何为外键关系定义对象级权限

时间:2019-02-08 22:08:30

标签: django permissions django-rest-framework serializer

我在ModelViewSet中为外键关系定义对象级权限时遇到麻烦。我不确定是否完全有可能我要做什么,或者是否有更好的解决方案,但是任何朝着正确方向的提示将不胜感激。为了简洁起见,我缩短了模型和序列化器。

我有以下型号:

class Team(models.Model):
    name = models.CharField(max_length=50)

class CustomUser(AbstractUser):
    teams = models.ManyToManyField(Team)

class Client(models.Model):
    name = models.CharField(max_length=50)
    owner = models.ForeignKey(Team, on_delete=models.CASCADE)

class FinancialAccount(models.Model):
    account_name = models.CharField(max_length=50)
    client = models.ForeignKey(Client, on_delete=models.CASCADE)

然后我有以下序列化器:

class ClientSerializer(serializers.ModelSerializer):
    class Meta:
        model = Client
        fields = ('name', 'owner')

class FinancialAccountSerializer(serializers.ModelSerializer):
    owner = serializers.SerializerMethodField()

    class Meta:
        model = FinancialAccount
        fields = ('name', 'client', 'owner')

    def get_owner(self, obj):
        return client.owner.name

然后,我试图定义一个可以在所有ModelViewSet中使用的权限。我希望它具有一定的动态性,因为我拥有的模型要多于与Client或以下FinancialAccount相关的模型。权限和视图集如下:

class IsOwnerTeam(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        teams = request.user.teams.values_list('name', flat=True)
        return obj.owner in teams

class FinancialAccountViewSet(viewsets.ModelViewSet):
    serializer_class = FinancialAccountSerializer
    permission_classes = (IsOwnerTeam, )

    def get_queryset(self):
        teams = self.request.user.teams.all()
        clients = Client.objects.filter(owner__in=teams)
        return FinancialAccount.objects.filter(account__in=accounts)

因此,现在我收到此错误:'FinancialAccount' object has no attribute 'owner',这是有道理的,因为我在FinancialAccount对象上没有所有者字段。但是,我想如果我在序列化程序中有一个owner字段(并在每个序列化程序中都放置一个owner字段),我可以用这种方式检索它。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

您可以执行以下操作:

class IsOwnerTeam(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        if hasattr(obj, 'client'):
            owner = obj.client.owner
        else:
            owner = obj.owner
        teams = request.user.teams.values_list('name', flat=True)
        return owner in teams