首页 > 解决方案 > Django Rest Framework - & on 方法过滤器无法按预期工作

问题描述

我的模型:

class Detail(models.Model):
    id = models.IntegerField(primary_key=True)
    entry_date = models.DateTimeField(null=True)

    class Meta:
        managed=False
        db_table = detail
class Item(models.Model):
    id = models.IntegerField(primary_key=True)
    name = models.Charfield(max_length=20)
    qty = models.IntegerField()
    
    @property
    def from_detail(self):
        return Detail.objects.filter(id=self.id).values('entry_date')

    class Meta:
        managed=False
        db_table=item

在我的过滤器集中,我正在执行以下操作:

class ItemFilter(FilterSet):
    entry_date__gte = DateTimeFilter(field_name='entry_date', method=entry_gte_filter)
    entry_date__lte = DateTimeFilter(field_name='entry_date', method=entry_lte_filter)

    class Meta:
        model = Item
        fields = ('name', 'qty', 'entry_date__gte', 'entry_date__lte')

出于某种原因,我必须在这里使用方法字段并且不能直接给出查找 expr

我的方法如下所示:

def entry_gte_filter(queryset, name, value):
    name = f"{name}__gte"
    queryset = Item.objects.annotate(
        detail=models.Exists(Detail.objects.filter(
            **{name: value, 'id': models.OuterRef('id')}))).filter(detail=True)

    return queryset

def entry_lte_filter(queryset, name, value):
    name = f"{name}__lte"
    queryset = Item.objects.annotate(
        detail=models.Exists(Detail.objects.filter(
            **{name: value, 'id': models.OuterRef('id')}))).filter(detail=True)

    return queryset

但是,当我执行以下 API 时:

GET /api/items?entry_date__gte=2021-06-29&entry_date__lte=2021-07-04

我收到以下输入日期的回复:

2021-06-30T00:00:00
2021-06-11T00:00:00
2021-07-02T00:00:00

我不清楚为什么当 API 提到 entry_date__gte=2021-06-29 时会返回 2021-06-11 的响应

在我看来,当使用方法类型时,django 过滤器没有按预期工作。任何人都可以在这里帮助我为什么 djangorestframework 的行为是这样的,是否有任何方法可以解决这个问题并获得预期的行为?

标签: djangodjango-rest-framework

解决方案


假设请求的视图配置正确并且ItemFilter过滤器及其方法(entry_lte_filter, entry_gte_filter)被执行,那么我看到两个原因它不起作用。

首先,在每个过滤方法中,您都从一个新的查询集 ( Model.objects) 开始。您应该使用queryset提供的作为参数并返回修改它的结果docs

其次,您尝试将datetimefield ( entry_date) 与表示 a 的字符串进行比较date。您可以在使用__date lookup时比较它们。

def entry_gte_filter(queryset, name, value):
    name = f"{name}__date__gte"
    queryset = queryset.annotate(
        detail_date_gte_exists=models.Exists(Detail.objects.filter(
            **{name: value, 'id': models.OuterRef('id')}))
    ).filter(detail_date_gte_exists=True)

    return queryset

def entry_lte_filter(queryset, name, value):
    name = f"{name}__date__lte"
    queryset = queryset.annotate(
        detail_date_lte_exists=models.Exists(Detail.objects.filter(
            **{name: value, 'id': models.OuterRef('id')}))
    ).filter(detail_date_lte_exists=True)

    return queryset

推荐阅读