如何在Django中按正反货币对组合分组查询ExchangeMarket模型?
解决方案
核心思路是给每个货币对生成标准化标识——不管base和quote的顺序如何,让同一货币对的正反方向拥有相同的分组键,再基于这个键聚合。
步骤1:生成标准化分组键并聚合
先导入需要的Django ORM工具:
from django.db.models import Case, When, F, IntegerField, ArrayAgg, Count
编写Queryset,通过Case/When生成两个标准化字段(取货币ID的最小值和最大值),再分组聚合:
# 生成标准化货币对,聚合同一组合(含正反方向)的所有主键 standardized_pairs = ExchangeMarket.objects.annotate( # 取base和quote中ID较小的货币作为统一基准 min_currency=Case( When(base_currency__lt=F('quote_currency'), then=F('base_currency')), default=F('quote_currency'), output_field=IntegerField() ), # 取ID较大的货币作为统一配对 max_currency=Case( When(base_currency__gt=F('quote_currency'), then=F('base_currency')), default=F('quote_currency'), output_field=IntegerField() ) ).values('min_currency', 'max_currency').annotate( # 收集该组合下所有条目的主键 pks=ArrayAgg('pk'), # 统计该组合下的条目数量(可选) total_count=Count('pk') )
这段代码会把EUR/USD和USD/EUR归到同一组,它们的min_currency都是EUR的ID,max_currency都是USD的ID。
步骤2:筛选并获取完整条目
如果只想保留存在正反方向的组合(比如排除只有BTC/USD没有USD/BTC的条目),可以加过滤条件:
# 只保留有至少2条的组合(即存在正反对) paired_pairs = standardized_pairs.filter(total_count__gt=1)
如果需要获取这些分组对应的完整ExchangeMarket对象,可以提取所有主键后查询:
# 提取所有相关主键 all_related_pks = [] for item in paired_pairs: all_related_pks.extend(item['pks']) # 获取完整对象列表 target_markets = ExchangeMarket.objects.filter(pk__in=all_related_pks)
如果使用PostgreSQL数据库,还可以用Unnest简化主键提取:
from django.contrib.postgres.functions import Unnest all_related_pks = paired_pairs.annotate(single_pk=Unnest('pks')).values_list('single_pk', flat=True) target_markets = ExchangeMarket.objects.filter(pk__in=all_related_pks)
内容的提问来源于stack exchange,提问作者ElRey777
相关产品推荐
相关产品推荐

