Django REST Framework中的私有和公共领域

时间:2019-05-27 22:24:27

标签: python django django-rest-framework

我想要一个公共和私人食谱的列表,隐藏所有私有食谱,除非它是所有者的。我为此创建了一个经理:

class RecipeManager(models.Manager):

    def public_recipes(self, *args, **kwargs):
        return super(RecipeManager, self).filter(private=False)

    def private_recipes(self, *args, **kwargs):
        user = kwargs.pop('user')
        return super(RecipeManager, self).filter(private=True, user=user)


class Recipe(models.Model):
    name = models.CharField(max_length=100)
    recipe = models.CharField(max_length=200)
    private = models.BooleanField(default=False)

views.py:

class RecipeViewSet(viewsets.ModelViewSet):
    queryset = Recipe.objects.all()
    serializer_class = RecipeSerializer
    permission_classes = (AllowAny,)

serializers.py:

class RecipeSerializer(serializers.ModelSerializer):

    class Meta:
        model = Recipe
        fields = ('id', 'name', 'recipe', 'total_ingredients')
        depth = 1

那么,在哪里可以使用方法public_recipesprivate_recipes,或者有更好的解决方案?

1 个答案:

答案 0 :(得分:0)

首先,您可能希望将自定义管理器设置为配方模型的默认管理器,如下所示:

class RecipeManager(models.Manager):

    def public_recipes(self, *args, **kwargs):
        return super(RecipeManager, self).filter(private=False)

    def private_recipes(self, *args, **kwargs):
        user = kwargs.pop('user')
        return super(RecipeManager, self).filter(private=True, user=user)


class Recipe(models.Model):
    name = models.CharField(max_length=100)
    recipe = models.CharField(max_length=200)
    private = models.BooleanField(default=False)

    objects = RecipeManager()  # Make this manager the default manager

您可以在视图上覆盖get_queryset()方法,以合并用户的私人和公共食谱:

class RecipeViewSet(viewsets.ModelViewSet):
    queryset = Recipe.objects.all()
    serializer_class = RecipeSerializer
    permission_classes = (AllowAny,)

    def get_queryset(self):
        if self.request.user:
            private_recipes = Recipe.objects.private_recipes(user=self.request.user)
        else:
            private_recipes = Recipe.objects.none()

        public_recipes = Recipe.objects.public_recipes()

        final_recipes_list = private_recipes | public_recipes # Shorthand to merge two querysets
        return final_recipes_list

我实际上建议考虑为公共和私人食谱使用不同的ViewSet,即

class PublicRecipeViewSet(viewsets.ModelViewSet):
    queryset = Recipe.objects.public_recipes()

class PrivateRecipeViewSet(viewsets.ModelViewSet):
    queryset = Recipe.objects.filter(private=True)

    def get_queryset(self):
        if not self.request.user:
            raise AuthenticationFailed()

        queryset = super().get_queryset()
        return queryset.filter(user=self.request.user)