Django Rest Framework过滤计算的模型属性

时间:2017-07-08 18:16:03

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

抱歉新手问题。我有以下模型:

my_strings

串行:

class WeightSlip(models.Model):

    grossdate = models.DateTimeField(auto_now=False, auto_now_add=False)
    grossweight = models.DecimalField(max_digits=6, decimal_places=2, default=0)
    taredate = models.DateTimeField(auto_now=False, auto_now_add=False)
    tareweight = models.DecimalField(max_digits=6, decimal_places=2, default=0)
    vehicle = models.CharField(max_length=12)

    @property
    def netweight(self):
        return self.grossweight - self.tareweight

    @property
    def slipdate(self):
        if self.grossdate > self.taredate:
           return grossdate.date()
        else:
           return taredate.date()

我正在尝试使用django-rest-framework-filters过滤计算出的' netweight'并且' slipdate'属性:

class WeightSlipSerializer(serializers.ModelSerializer):

   class Meta:
      model = models.WeightSlip
      fields = ('grossdate', 'grossweight', 'taredate', 'tareweight', 'slipdate', 'netweight', 'vehicle')
      read_only_fields = ('slipdate', 'netweight')

这给了我一个错误:

class WeightSlipFilter(FilterSet):

   class Meta:
       model = WeightSlip
       fields = ('slipdate', 'netweight', 'vehicle')

除了将计算字段添加到数据库之外,是否有解决此问题的方法?

提前致谢。

3 个答案:

答案 0 :(得分:7)

您可以为slipdate, netweight创建自定义过滤器,以便在db中评估和过滤此字段。为此,您可以使用conditional expressionsF expression

from django.db.models import F, Case, When

class WeightSlipFilter(FilterSet):
    slipdate = DateTimeFilter(method='filter_slipdate')
    netweight = NumberFilter(method='filter_netweight')

    class Meta:
        model = WeightSlip
        fields = ('slipdate', 'netweight', 'vehicle')

    def filter_netweight(self, queryset, value):
        if value:
            queryset = queryset.annotate(netweight=F('grossweight') - F('tareweight')).filter(netweight=value)
        return queryset

    def filter_slipdate(self, queryset, value):
        if value:
            queryset = queryset.annotate(slipdate=Case(When(grossdate__gt=F('taredate'), then=F('grossdate')), default=F('taredate')).filter(slipdate=value)
        return queryset

答案 1 :(得分:2)

请注意,如果您使用的是最新版本的django-filter,Filter.method需要4个参数,如下所示:

def filter_slipdate(self, queryset, name, value):
    if value:
        queryset = queryset.annotate(slipdate=Case(When(grossdate__gt=F('taredate'), then=F('grossdate')), default=F('taredate')).filter(slipdate=value)
    return queryset

```

答案 2 :(得分:0)

进一步扩展答案。使用最新的django和drf版本,可能会遇到这样的异常。

例外

it 中的文件“ /home/USER/.env/drf3/lib64/python3.7/site-packages/django/db/models/query.py”,第76行 setattr(obj,attr_name,row [col_pos]) AttributeError:无法设置属性

使用的版本Django==3.1 djangorestframework==3.11.1 django-filter==2.3.0

对我有用的解决方案是这样的,其中slipdate和netweight要求在查询集中使用模型名称...

def filter_slipdate(self, queryset, name, value):
    if value:
       queryset = queryset.annotate(WeightSlip__slipdate=Case(When(grossdate__gt=F('taredate'), then=F('grossdate')), default=F('taredate'))).filter(WeightSlip__slipdate=value)
    return queryset

def filter_netweight(self, queryset, name, value):
    if value:
        queryset = queryset.annotate(WeightSlip__netweight=F('grossweight') - F('tareweight')).filter(WeightSlip__netweight=value)
    return queryset
    return queryset