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

Django中Filter查询相册返回重复条目问题求助

问题描述

我定义了两个Django模型:

class PhotoAlbum(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, auto_created=True)
    name = models.CharField(max_length=50, verbose_name='Album name')

class AlbumImage(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, auto_created=True)
    album = models.ForeignKey(PhotoAlbum, on_delete=models.CASCADE, related_name='photos')
    image = models.ImageField(upload_to='images/', height_field=None, width_field=None, max_length=100, blank=True)

发送不带查询参数的GET请求时,能得到正常响应(示例为一个随机条目):

[
    {
        "id": 1,
        "name": "Album name",
        "photos": [
            {
                "id": 2,
                "url": "http://localhost:8000/media/random_image_one.png"
            },
            {
                "id": 3,
                "url": "http://localhost:8000/media/random_image_two.png"
            }
        ]
    }
]

但重写get_queryset方法后出现问题:

has_photos = self.request.query_params.get('has_photos')
if has_photos == 'true':
    return PhotoAlbum.objects.filter(photos__isnull=False)
elif has_photos == 'false':
    return PhotoAlbum.objects.filter(photos__isnull=True)

当has_photos='true'时,响应结果会为相册中的每张照片返回一条重复的相册条目。比如相册关联了10个AlbumImage对象,就会返回10条相同的相册条目而非1条。请问哪里出错了?


解决方案

这是因为Django执行photos__isnull=False这类关联过滤时,会生成SQL JOIN操作,将PhotoAlbum和AlbumImage表关联。如果一个相册有N张照片,JOIN后的结果集中就会有N条对应这个相册的记录,最终序列化时就会输出N条重复的相册数据。

有两种解决方法:

  1. 使用distinct()去重
    在查询集末尾添加distinct(),让Django返回唯一的相册记录:

    has_photos = self.request.query_params.get('has_photos')
    if has_photos == 'true':
        return PhotoAlbum.objects.filter(photos__isnull=False).distinct()
    elif has_photos == 'false':
        return PhotoAlbum.objects.filter(photos__isnull=True).distinct()
    
  2. 使用exists子查询(性能更优)
    通过子查询判断相册是否存在关联照片,避免JOIN操作,数据量较大时性能更好:

    from django.db.models import Exists, OuterRef
    
    has_photos = self.request.query_params.get('has_photos')
    if has_photos == 'true':
        return PhotoAlbum.objects.filter(Exists(AlbumImage.objects.filter(album=OuterRef('pk'))))
    elif has_photos == 'false':
        return PhotoAlbum.objects.filter(~Exists(AlbumImage.objects.filter(album=OuterRef('pk'))))
    

两种方法都能解决重复问题,可根据实际数据规模选择。

内容的提问来源于stack exchange,提问作者Anonymous Wizard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 13:25:32