Django如何在视图中对模型@property自定义属性实现查询过滤
解决方案
核心原因:@property 是Python实例层面的属性,仅在模型实例化后才会计算,而Django ORM的filter方法会转换为SQL语句在数据库层面执行,数据库不存在这个字段,因此无法直接过滤。
方案1:直接改写过滤逻辑(最快实现)
你不需要自定义管理器也能实现需求,直接将product_name的关联逻辑通过F表达式(用于引用当前表的字段值)转换为ORM跨表过滤即可:
from django.db.models import F filtered_product = TransactionData.objects.filter( Site=Site_id, # 关联Nozzle表的条件完全匹配你@property里的逻辑 Nozzle__Pump__Device__Device_unique_address=F("Pump_mac_address"), Nozzle__Nozzle_address=F("Nozzle_address"), # 直接过滤产品名 Nozzle__Product__Name="kero" )
方案2:自定义查询集实现链式调用(符合你预期的调用形式)
如果想要复用该逻辑,实现你提到的filter(...).product_name(xxx)的链式调用,你可以自定义查询集绑定到模型:
第一步:定义自定义查询集
from django.db.models import QuerySet, F class TransactionDataQuerySet(QuerySet): def product_name(self, name): return self.filter( Nozzle__Pump__Device__Device_unique_address=F("Pump_mac_address"), Nozzle__Nozzle_address=F("Nozzle_address"), Nozzle__Product__Name=name )
第二步:绑定到模型
class TransactionData(models.Model): # 你原有字段定义 Nozzle_address = models.CharField(max_length=255) Device = models.ForeignKey(Devices, on_delete=models.CASCADE) Site = models.ForeignKey(Sites, on_delete=models.CASCADE, related_name='transaction_data') Pump_mac_address = models.CharField(max_length=255) # 绑定自定义查询集作为管理器 objects = TransactionDataQuerySet.as_manager() # 你原有@property,注意修正原代码的bug:filter返回查询集不能直接取Product,需要先获取单条实例 @property def product_name(self): try: return Nozzle.objects.get( Pump__Device__Device_unique_address=self.Pump_mac_address, Nozzle_address=self.Nozzle_address ).Product.Name except: return None
第三步:使用方式
filtered_product = TransactionData.objects.filter(Site=Site_id).product_name('kero')
方案3:用Subquery注解实现直接过滤product_name
如果你希望可以直接在filter中使用product_name作为查询条件,可以通过子查询注解将字段注入到查询集中:
from django.db.models import OuterRef, Subquery # 定义子查询,匹配每行TransactionData的对应产品名 product_name_subq = Nozzle.objects.filter( Pump__Device__Device_unique_address=OuterRef("Pump_mac_address"), Nozzle_address=OuterRef("Nozzle_address") ).values("Product__Name")[:1] # 注解后直接过滤 filtered_product = TransactionData.objects.annotate( product_name=Subquery(product_name_subq) ).filter(Site=Site_id, product_name="kero")
原有代码问题修正
你之前的注解失败是因为注解阶段没有模型实例,不存在self变量,需要用OuterRef引用外层查询的当前行字段,而非self。同时你原有@property中使用filter后直接取Product会报错,因为filter返回的是查询集而非单个实例,需要改为get或者加first()获取单条结果。
内容的提问来源于stack exchange,提问作者Ridwanray
相关产品推荐
相关产品推荐

