Django models 带有特殊子句的Django过滤器ManyToManyField
我在Django 1.8下。我有几个播放列表,每个列表包含几个视频。其中一些视频的状态为“已删除”或“错误” 我只想要包含状态为“在线”的视频的播放列表。Django models 带有特殊子句的Django过滤器ManyToManyField,django-models,many-to-many,django-1.8,Django Models,Many To Many,Django 1.8,我在Django 1.8下。我有几个播放列表,每个列表包含几个视频。其中一些视频的状态为“已删除”或“错误” 我只想要包含状态为“在线”的视频的播放列表。 class Video(models.Model): # Title of the video title = models.CharField(max_length=100) # Status of video (error, online, deleted) status = models.Cha
class Video(models.Model):
# Title of the video
title = models.CharField(max_length=100)
# Status of video (error, online, deleted)
status = models.CharField(max_length=20, default="online")
class UserPlaylist(models.Model):
# Name of the playlist
name = models.CharField(max_length=500, blank=True, null=True)
# Playlist owner
owner = models.ForeignKey(User)
# videos
videos = models.ManyToManyField(Video, null=False)
我的尝试没有成功:
UserPlaylist.objects.filter(videos__status="online")
UserPlaylist.objects.filter(videos__status="online").distinct()
工作但痛苦:
UserPlaylist.objects.exclude(videos__status='error').exclude(videos__status='deleted').distinct()
我们可以使用
status='online'
统计视频的数量,并检查这是否与视频总数相同,如:
from django.db.models import Case, F, Q, When
UserPlaylist.objects.annotate(
nvideo=Count('videos'),
nonline=Count(Case(
When(videos__status='online', then='videos'),
default=None
))
).filter(
nvideo=F('nonline')
)
这将生成一个如下所示的查询:
SELECT userplaylist.id, userplaylist.name,
COUNT(userplaylist_videos.video_id) AS nvideo,
COUNT(CASE WHEN video.status = online
THEN userplaylist_videos.video_id
ELSE NULL END) AS nonline
FROM userplaylist
LEFT OUTER JOIN userplaylist_videos
ON userplaylist.id = userplaylist_videos.userplaylist_id
LEFT OUTER JOIN video ON userplaylist_videos.video_id = video.id
GROUP BY userplaylist.id
HAVING COUNT(userplaylist_videos.video_id) = COUNT(
CASE WHEN video.status = online
THEN userplaylist_videos.video_id
ELSE NULL END)
请注意,不包含视频的UserPlaylist
也将是结果的一部分,因为它的所有视频都是在线的。我们可以使用status='online'
计算视频的数量,并检查这是否与总视频的数量相同,如:
from django.db.models import Case, F, Q, When
UserPlaylist.objects.annotate(
nvideo=Count('videos'),
nonline=Count(Case(
When(videos__status='online', then='videos'),
default=None
))
).filter(
nvideo=F('nonline')
)
这将生成一个如下所示的查询:
SELECT userplaylist.id, userplaylist.name,
COUNT(userplaylist_videos.video_id) AS nvideo,
COUNT(CASE WHEN video.status = online
THEN userplaylist_videos.video_id
ELSE NULL END) AS nonline
FROM userplaylist
LEFT OUTER JOIN userplaylist_videos
ON userplaylist.id = userplaylist_videos.userplaylist_id
LEFT OUTER JOIN video ON userplaylist_videos.video_id = video.id
GROUP BY userplaylist.id
HAVING COUNT(userplaylist_videos.video_id) = COUNT(
CASE WHEN video.status = online
THEN userplaylist_videos.video_id
ELSE NULL END)
请注意,不包含视频的UserPlaylist
也将是结果的一部分,因为它的所有视频都是在线的。该尝试有什么不起作用?如果UserPlaylist
至少包含一个状态为online
的视频,则UserPlaylist
将位于该查询集中。也许这不是你想要的?@WillemVanOnsem它会返回所有视频的列表,不管状态如何。我尝试使用distinct,它会返回我所有的播放列表,但里面仍然有状态不同于在线的视频。我只想要一个只有播放列表的查询集,里面的所有视频都是“在线”的。我可以添加一个排除过滤器,但它似乎非常不适合。不包括(VixOsSyStase=‘错误’)。排除(VixOsSyStase=“已删除”),虽然我认为它可以被解决(用这个答案),但是你应该考虑升级。Django-1.8不再受支持,2018年4月。这种尝试有什么不起作用?如果UserPlaylist
至少包含一个状态为online
的视频,则UserPlaylist
将位于该查询集中。也许这不是你想要的?@WillemVanOnsem它会返回所有视频的列表,不管状态如何。我尝试使用distinct,它会返回我所有的播放列表,但里面仍然有状态不同于在线的视频。我只想要一个只有播放列表的查询集,里面的所有视频都是“在线”的。我可以添加一个排除过滤器,但它似乎非常不适合。不包括(VixOsSyStase=‘错误’)。排除(VixOsSyStase=“已删除”),虽然我认为它可以被解决(用这个答案),但是你应该考虑升级。Django-1.8不再受支持,2018年4月。学到了很多,不知道什么时候/案例。谢谢!学到了很多,不知道什么时候/情况。谢谢!