Django Rest Framework 过滤计算模型属性
Posted
技术标签:
【中文标题】Django Rest Framework 过滤计算模型属性【英文标题】:Django Rest Framework filtering calculated model property 【发布时间】:2017-12-12 20:23:56 【问题描述】:抱歉,有一个新手问题。我有以下型号:
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()
序列化器:
class WeightSlipSerializer(serializers.ModelSerializer):
class Meta:
model = models.WeightSlip
fields = ('grossdate', 'grossweight', 'taredate', 'tareweight', 'slipdate', 'netweight', 'vehicle')
read_only_fields = ('slipdate', 'netweight')
我正在尝试使用django-rest-framework-filters 过滤计算的“净重”和“滑动日期”属性:
class WeightSlipFilter(FilterSet):
class Meta:
model = WeightSlip
fields = ('slipdate', 'netweight', 'vehicle')
这给了我一个错误:
TypeError: 'Meta.fields' contains fields that are not defined on this FilterSet: slipdate, netweight
除了将计算字段添加到数据库之外,还有其他解决方法吗?
提前致谢。
【问题讨论】:
【参考方案1】:您可以为 slipdate, netweight
创建自定义过滤器,它将评估和过滤 db 中的此字段。为此,您可以使用 conditional expressions 和 F 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
【讨论】:
非常感谢,很大的帮助,因为我的大部分项目都包含对计算字段的过滤。 从 django_filters.rest_framework 导入(NumberFilter、DateTimeFilter、)【参考方案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
```
【讨论】:
【参考方案3】:进一步扩展答案。使用最新的 django 和 drf 版本可能会遇到这样的异常。
例外
iter 中的文件“/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
【讨论】:
以上是关于Django Rest Framework 过滤计算模型属性的主要内容,如果未能解决你的问题,请参考以下文章
Django - 如何使用 Django Rest Framework 按日期过滤?
在带有 django-rest-framework 的过滤器中使用自定义方法
django-rest-framework- 使用“或”过滤来自一个 url 参数的多个值
Django Rest Framework 过滤计算模型属性