【问题标题】:Django RestFramework method filter with multiple lookups具有多个查找的 Django Rest Framework 方法过滤器
【发布时间】:2018-02-23 22:05:36
【问题描述】:

我有两个这样定义的模型:

class House(models.Model):
    # all the fields here

    def capacity(self):
        capacity = 0
        for room in self.rooms.all():
            capacity += room.capacity
        return capacity

class Room(models.Model):
    house = models.ForeignKey(
        House, 
        on_delete=models.CASCADE,
        related_name='rooms'
    )
    capacity = models.PositiveIntegerField(
        default=1
    )

我需要的是使用restframework中的所有数字查找(lt,lte,gt,gte,范围,精确)按容量过滤房屋,我这样做了:

import rest_framework_filters as filters

def capacity_filter(qs, name, value):
    # filter implementation here

class HouseFilter(filters.FilterSet):
    capacity = filters.NumberFilter(
        method=capacity_filter
    )

    class Meta:
        fields = ('capacity',)

class HouseViewSet(viewsets.ModelViewSet):
    filter_class = HouseFilter
    # other attrs here

它有效,但仅适用于精确值,我无法使用 __gt 或 __lt 进行过滤,我尝试使用 NumberFilter 中的 lookup_expr 参数但不起作用。

【问题讨论】:

    标签: django django-rest-framework django-filter


    【解决方案1】:

    【讨论】:

    • 我也试过了,但是方法参数不起作用,它会引发这个异常:'Meta.fields' contains fields that not defined on this FilterSet: capacity
    【解决方案2】:

    您可以使用部分生成具有适当查找的可调用对象。例如,

    def capacity_filter(qs, name, value, lookup_expr):
        # implementation
    
    class HouseFilter(filters.FilterSet):
        capacity = filters.NumberFilter(
            name='capacity',
            method=partial(capacity_filter, lookup_expr='exact'))
        capacity__lt = filters.NumberFilter(
            name='capacity',
            method=partial(capacity_filter, lookup_expr='lt'))
        ...
    

    也就是说,您可能应该使用注释来计算房间容量,因为它将在数据库中而不是在内存中执行计算。这也将允许您在此处放弃使用 method 参数。

    # the query you want to construct
    queryset = House.objects \
        .annotate(capacity=Sum('rooms__capacity'))
        .filter(...)
    
    # filterset
    class HouseFilter(FilterSet):
        capacity = filters.NumberFilter(
            name='capacity', lookup_expr='exact', 
            label='Capacity is equal to')
        capacity__lt = filters.NumberFilter(
            name='capacity', lookup_expr='lt', 
            label='Capacity is less than')
    
        @property
        def qs(self):
            # Only annotate capacity if filtering by capacity
            if not hasattr(self, '_qs') and self.form.is_valid() \
               and any(f.startswith('capacity') for f in self.form.cleaned_data):
                self.queryset = self.queryset \
                    .annotate(capacity=Sum('rooms__capacity'))
    
            return super(HouseFilter, self).qs
    

    【讨论】:

      猜你喜欢
      • 2019-05-15
      • 2015-06-04
      • 2017-06-13
      • 2018-10-03
      • 2017-01-15
      • 1970-01-01
      • 2018-07-28
      • 2021-03-09
      • 2021-09-15
      相关资源
      最近更新 更多