【问题标题】:Django REST; use queryset on a manytomany field to filter that related fieldDjango 休息;在多对多字段上使用查询集来过滤该相关字段
【发布时间】:2019-09-27 18:27:47
【问题描述】:

我正在使用 Django REST 框架,但无法弄清楚如何过滤查询引用模型/视图时返回的子字段(多对多字段)的结果。

我有一个 Tag 模型,它通过多对多字段与 Book 模型相关联。查询标签时,它会返回与其关联的所有书籍。但是,我需要过滤书籍以仅包含当前用户有权访问的书籍。

可以在书本视图中正确过滤,但我不知道如何让它在标签视图中工作

// Book model:
class BookQuerySet(models.QuerySet):
    def visible_to(self, user):
        if user.can_see_secrets:
            return self
        return self.exclude(secret_book=True)


class Book(models.Model):
    id = models.AutoField(db_column='Id', primary_key=True)
    name = models.CharField(db_column='CatalogNumber', unique=True, max_length=50)
    secret_book = models.IntegerField(db_column='secret', default=False)
    objects = BookQuerySet.as_manager()

    class Meta:
        managed = False
        db_table = 'book'
        app_label = 'core'


// Book view:
class BooksFilteringBackend(filters.BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        current_user = request.user
        queryset = queryset.visible_to(current_user)
        return queryset

class BookViewSet(viewsets.ReadOnlyModelViewSet):
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)
    queryset = Book.objects.all()
    filter_backends = (BooksFilteringBackend,)
    serializer_class = BookSerializer

There is a BookSerializer that doesnt do anything interesting

现在上述方法有效,如果用户查询图书视图,他们只会获得他们应该能够看到的图书。

这是我的问题:

// Tag model
class Tag(models.Model):
    id = models.AutoField(db_column='Id', primary_key=True)
    description = models.CharField(db_column='Description', unique=True, max_length=255)
    books = models.ManyToManyField('core.Book', through='BookTag', related_name='tags')

    class Meta:
        managed = False
        db_table = 'tag'
        app_label = 'tags'

// Tag viewset
class TagViewSet(viewsets.ReadOnlyModelViewSet):
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)
    queryset = Tag.objects.all()
    serializer_class = TagSerializer

// Tag serializer
class TagSerializer(serializers.ModelSerializer):
    id = serializers.ReadOnlyField()
    description = serializers.CharField(max_length=255)
    books = BookSerializer(many=True, read_only=True)

    class Meta:
        model = Tag
        fields = ('id',
                  'description',
                  'books',)

如果我点击标签视图集,我会得到与标签关联的所有书籍,因为我没有根据上述相同的逻辑过滤掉这些书籍。 当我拉标签时,我怎样才能做到这一点,我可以使用 BookQuerySet 或类似的东西。

欣赏任何见解!

【问题讨论】:

  • 您在寻找嵌套路由吗?
  • @schillingt 介意详细说明吗?我不确定到底是什么。
  • 基本上/book/1/tags/a-tag/ 在那里您为 Book 设置了一个视图,然后另一个视图集假定 URL 中有一个 book kwarg 要过滤到。
  • 如果您只想通过一些 ForeignKey 选择性过滤,那么我建议您查看 django-filter (django-filter.readthedocs.io/en/master/guide/…)

标签: django django-models django-rest-framework django-views


【解决方案1】:

找到答案:How do you filter a nested serializer in Django Rest Framework?

诀窍是在序列化程序级别执行此操作。显然,在标签序列化程序引用书籍序列化程序的地方,书籍的查询是 all(),因此您可以覆盖它:

在我无趣的书籍序列化文件中:

// added:
class BookFilteredListSerializer(serializers.ListSerializer):
    def to_representation(self, data):
        data = data.visible_to(self.context['request'].user)
        return super(BookFilteredListSerializer, self).to_representation(data)

// And then reference this from the actual BookSerializer meta:
class WorkSerializer(serializers.ModelSerializer):

     ...

     class Meta:
         model = Work
         list_serializer_class = WorkFilteredListSerializer
         fields = (...)

现在,当我查询标签端点并加载它时,标签使用这个过滤系统。

【讨论】:

    猜你喜欢
    • 2020-06-16
    • 2013-08-18
    • 2011-04-07
    • 2019-01-29
    • 1970-01-01
    • 2017-03-09
    • 2018-06-07
    • 2015-07-18
    • 1970-01-01
    相关资源
    最近更新 更多