具有特定子句的 Django Filter ManyToManyField
Django Filter ManyToManyField with particular clause
我使用的是 Django 1.8。我有几个播放列表,每个播放列表包含几个视频。其中一些视频的状态为已删除或错误。
我只想要包含状态为 "online" 的视频的播放列表。
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'
来计算 Video
的数量,并检查它是否与总视频数相同,例如:
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
也将成为结果的一部分,因为它的所有视频都在线。
我使用的是 Django 1.8。我有几个播放列表,每个播放列表包含几个视频。其中一些视频的状态为已删除或错误。
我只想要包含状态为 "online" 的视频的播放列表。
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'
来计算 Video
的数量,并检查它是否与总视频数相同,例如:
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
也将成为结果的一部分,因为它的所有视频都在线。