Django中能否将模型类方法作为Filter参数?
Django模型自定义方法能不能用来做Filter查询?
直接说结论:不行,这么写会报错。
为啥不行?
Django的QuerySet是把查询转成SQL在数据库里执行的,你写的dentrorev和forarev是模型实例的Python方法——这些逻辑是在Python代码层面运行的,数据库根本看不懂。直接用filter(dentrorev=True),Django会默认你要查询一个叫dentrorev的数据库字段,自然会抛出字段不存在的错误。
怎么改才能实现需求?
得把这两个方法里的逻辑,转成数据库能理解的ORM查询语句:
1. 把dentrorev的逻辑转成ORM查询
这个方法是判断最后一次使用的数值取模后是否在指定区间,用Subquery获取每个资产的最新使用记录,再通过annotate计算出布尔状态:
from django.db.models import Subquery, OuterRef, Case, When, BooleanField, F # 子查询:获取每个Bens对应的最新Usos的valor值 latest_uso_valor = Usos.objects.filter(bem=OuterRef('codigo')).order_by('-data').values('valor')[:1] # 计算dentrorev状态并过滤符合条件的资产 dentrorev_bens = Bens.objects.annotate( ultimo_uso_valor=Subquery(latest_uso_valor), margem_atual=F('ultimo_uso_valor') % F('periodoRevisao'), dentrorev=Case( When( (F('margem_atual') >= F('periodoRevisao') - F('margemRevisao')) & (F('margem_atual') <= F('periodoRevisao')) | (F('margem_atual') >= 0) & (F('margem_atual') <= F('margemRevisao')), then=True ), default=False, output_field=BooleanField() ) ).filter(dentrorev=True)
2. 把forarev的逻辑转成ORM查询
这个方法是判断资产有没有未完成的工单,用Exists子查询更高效,避免在内存中生成大列表:
from django.db.models import Exists, OuterRef # 子查询:检查当前资产是否存在未完成的工单(listaStatus不等于4) has_open_order = OrdensServicos.objects.filter( ordemServico__uso__bem__codigo=OuterRef('codigo'), listaStatus__ne='4' ).distinct() # 过滤出没有未完成工单的资产(即forarev=True的情况) forarev_bens = Bens.objects.annotate( forarev=Case( When(Exists(has_open_order), then=False), default=True, output_field=BooleanField() ) ).filter(forarev=True)
3. 合并查询结果
最后用union合并两个QuerySet,和你原本的逻辑保持一致:
revisao = dentrorev_bens.union(forarev_bens)
额外提示
尽量把数据处理逻辑下推到数据库端执行,比在Python层面处理大量数据的性能要好得多。如果这些查询逻辑需要多次复用,可以封装成模型管理器(Manager)方法或者自定义QuerySet方法,方便后续调用。
内容的提问来源于stack exchange,提问作者iranilson
相关产品推荐
相关产品推荐

