【问题标题】:Applying a Django FilterSet to an Annotated QuerySet?将 Django 过滤器集应用于带注释的查询集?
【发布时间】:2018-12-08 03:54:33
【问题描述】:

我正在尝试将过滤器应用于带注释的查询集,就像这里所做的那样: https://docs.djangoproject.com/en/2.0/topics/db/aggregation/#filtering-on-annotations

和下面的 sn-p 类似,我想把 highly_rated 做成一个 FilterSet 来获取请求参数

highly_rated = Count('books', filter=Q(books__rating__gte=7))
Author.objects.annotate(num_books=Count('books'), highly_rated_books=highly_rated)

我想让highly_rated 成为一个过滤器集,用于接收请求查询。比如:

class MainFilter(FilterSet):
    class Meta:
        model = Author
        fields = {
            author: ['in', 'exact'],
            genre: ['in', 'exact']
        }

class AnnotatedFilter(FilterSet):
    class Meta:
        fields = {
            'books__rating': ['gt', 'lt' ],
        }

class MyView(ListApiView):
    filter_class = AuthorFilter

    def get_queryset(self):
        annotated_filter = AnnotatedFilter(request) # how do I set up another filter based on the request?
        Author.objects.annotate(num_books=Count('books'), FilterSet=annotated_filter) # how do I apply it to an annotated queryset?

所以我可以查询如下内容:

api/authors/?genre=Fantasy&books__rating__gt=5

其中一个参数针对所有记录执行,其他参数针对注释部分执行。

非常感谢任何帮助。谢谢!

【问题讨论】:

    标签: django django-rest-framework django-filters


    【解决方案1】:

    get_queryset()方法改为

    def get_queryset(self):
        return Author.objects.annotate(num_books=Count('books')
    


    并将Filter class 中的该字段定义为

    class AuthorFilter(FilterSet):
        num_books = filters.NumberFilter(name='num_books')
        class Meta:
            model = Author
            fields = ['num_books',]#other fields
    

    然后将 api 用作/api/end/point/authorlist/?num_books=10

    示例

    models.py

    from django.db import models
    
    
    class Sample(models.Model):
        foo = models.IntegerField()
        bar = models.IntegerField()
    

    views.py

    from django.db.models import F
    from django_filters import rest_framework as filters
    
    
    class MySampleAPI(viewsets.ModelViewSet):
        filter_backends = (filters.DjangoFilterBackend,)
        filter_class = SampleFilterClass
        serializer_class = SampleSerializerClass
    
        def get_queryset(self):
            return Sample.objects.annotate(foo_bar_sum=F('foo') + F('bar'))
    

    filters.py

    from django_filters import rest_framework as filters
    
    
    class SampleFilterClass(filters.FilterSet):
        sum = filters.NumberFilter(name='foo_bar_sum', lookup_expr='gte')
    
        class Meta:
            model = Sample
            fields = ['sum', ]
    

    【讨论】:

    • 我必须将 'name' 更改为 'field_name' 才能使其与最新版本的 django-filters 一起使用。
    【解决方案2】:

    JPG 的答案对我有用,但我不得不在过滤器类中用标签替换名称:

    class AuthorFilter(FilterSet):
        num_books = filters.NumberFilter(label='num_books')  # here
        class Meta:
            model = Author
            fields = ['num_books',]#other fields
    

    【讨论】:

      猜你喜欢
      • 2020-05-14
      • 2018-12-23
      • 2019-04-03
      • 2019-07-29
      • 1970-01-01
      • 2019-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多