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条重复的相册数据。
有两种解决方法:
使用
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()使用
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
相关产品推荐
相关产品推荐

