Annotate + Distinct Not Implemented,算一个Distinct子查询

Annotate + Distinct Not Implemented, Count a Distinct Subquery

我有两个模型,RetailLocation 和 Transaction,它们分别共享一对多关系。我试图注释 RetailLocation 有任意数量的交易的总天数(计数)。在这样做时,我将 Transaction.date 字段过滤为日期而不是日期时间,并尝试 SELECT DISTINCT 日期,但 运行 进入错误“NotImplementedError: annotate() + distinct(fields) 未实现。"

型号

class RetailLocation(models.Model):
    name = models.CharField(max_length=200, null=True)

class Transaction(models.Model):
    date = models.DateTimeField(null=True)
    r_loc = models.ForeignKey(RetailLocation, null=True, on_delete=models.SET_NULL)

尝试的代码

test = RetailLocation.objects.annotate(                                                    
    days_operating=Subquery(                                                     
        Transaction.objects.filter(r_loc=OuterRef("pk"))                          
        .distinct('date__date')                                                  
        .annotate(count=Count('pk'))                                             
        .values('count')                                                         
    )                                                                            
)

in combination with ,但使用 distinct 似乎会导致上面提到的 NotImplementedError。我相信也可能有一个使用 Count( , distinct=True) 的解决方案,但它不会有帮助,除非我可以在 date__date 上区分,因为我只是想找到发生任意数量事务的日期。

非常感谢您抽出宝贵时间。

方案一(使用外键)

RetailLocation.objects.annotate(days_operating=Count('transaction__date__date', distinct=True))

使用 RetailLocation 和 Transaction 之间的 ForeignKey 关系,首先按照 ForeignKey 获取相关的 Transaction 对象集 ('transaction'),然后 select 'date' 列 ('transaction_date'),最后将其转换为日期 ('transaction_date_date')。 returns 字典列表 {date_date: 日期对象},并使用 Count( , distinct=True) 计算唯一日期集。

解决方案 2(使用子查询)

test = RetailLocation.objects.annotate(                                                    
    days_operating=Subquery(                                                     
    Transaction.objects.filter(r_loc=OuterRef("pk"))
    .values('r_loc')
    .annotate(count=Count('date__date', distinct=True))                                             
    .values('count')
    )
)
                                                                      

这与解决方案 1 的工作方式基本相同,但如果您想根据其他内容进行过滤,则 不需要 在两个模型之间建立外键关系 (也许是日期)。

Useful link on Subquery Aggregation