You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django查询如何过滤多对多关联中首个艺术家符合条件的歌曲

解决方案

要实现按关联的首个艺术家过滤,首先需要明确多对多关联中「第一个」的排序规则(必须和song.artists.first()的排序逻辑一致,默认是关联表的自增ID升序),以下是两种可行方案:


方案1:数据库层面查询(推荐,性能更好,支持分页等操作)

使用Django的窗口函数+子查询实现,适合数据量较大的场景:

from django.db.models import Subquery, OuterRef, Window, F
from django.db.models.functions import RowNumber

# 构造子查询:获取每首歌的首个关联艺术家ID
first_artist_subquery = Artist.objects.filter(
    song__id=OuterRef('pk')
).annotate(
    # 按歌曲分组,给同一首歌的关联艺术家按规则排序并编号
    artist_order=Window(
        expression=RowNumber(),
        partition_by=F('song__id'),
        # 此处排序规则必须和你调用 song.artists.first() 的排序完全一致
        # 如果是按关联时间先后,默认可以写 order_by=F('id').asc()
        # 如果多对多有中间表且有排序字段,可替换为 order_by=F('中间表名__排序字段').asc()
        order_by=F('id').asc()
    )
).filter(
    artist_order=1 # 取编号为1的首个艺术家
).values('id')[:1]

# 过滤符合条件的歌曲
target_songs = Song.objects.annotate(
    first_artist_id=Subquery(first_artist_subquery)
).filter(
    first_artist_id__country__code__in=['NL', 'BE']
)

方案2:Python层面过滤(仅适合小数据量场景)

直接遍历所有歌曲,在内存中判断首个艺术家的国家,代码更简单但数据量大时性能差:

target_songs = []
# 预加载关联艺术家避免N+1查询
for song in Song.objects.prefetch_related('artists'):
    first_artist = song.artists.first()
    if first_artist and first_artist.country and first_artist.country.code in ('NL', 'BE'):
        target_songs.append(song)

注意事项

  • 如果你自定义了Artist模型的Meta.ordering,或者多对多关联有自定义排序规则,必须修改方案1中子查询的order_by参数,保证和first()的排序逻辑一致,否则查询结果会不符
  • 无关联艺术家、或首个艺术家无国家信息的歌曲会默认被过滤,如有需要可以额外调整过滤条件保留对应数据

内容的提问来源于stack exchange,提问作者A. Nurb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 20:54:08