2012-04-16 109 views
6

整个查询集我有以下型号:排除从结果

class LibraryEntry(models.Model): 
    player = models.ForeignKey(Player) 
    player_lib_song_id = models.IntegerField() 
    title = models.CharField(max_length=200) 
    artist = models.CharField(max_length=200) 
    album = models.CharField(max_length=200) 
    track = models.IntegerField() 
    genre = models.CharField(max_length=50) 
    duration = models.IntegerField() 
    is_deleted = models.BooleanField(default=False) 

    class Meta: 
    unique_together = ("player", "player_lib_song_id") 

    def __unicode__(self): 
    return "Library Entry " + str(self.player_lib_song_id) + ": " + self.title 

class BannedSong(models.Model): 
    lib_entry = models.ForeignKey(LibraryEntry) 

    def __unicode__(self): 
    return "Banned Library Entry " + str(self.lib_entry.title) 

我愿意做这样的查询:

banned_songs = BannedSong.objects.filter(lib_entry__player=activePlayer) 
available_songs = LibraryEntry.objects.filter(player=activePlayer).exclude(banned_songs) 

基本上如果一首歌曲被禁止,我想排除它来自我的可用歌曲集。有没有办法在Django中做到这一点?

+0

你能不能让 'is_banned' 你LibraryEntry的模型的布尔字段? – jimw 2012-04-16 23:17:47

+0

是的,但实际上禁止的歌曲数量与没有的歌曲数量相比实际上会被禁止。我想添加一个布尔型字段,大多数情况下只会是一个值是不好的形式。 – 2012-04-16 23:19:40

+1

我不会这么说,但我认为这是一个品味问题。 – jimw 2012-04-16 23:21:05

回答

11
banned_song_ids = (BannedSong.objects.filter(lib_entry__player=activePlayer) 
              .values_list('lib_entry', flat=True)) 

available_songs = (LibraryEntry.objects.filter(player=activePlayer) 
              .exclude('id__in' = banned_song_ids)) 

另一种方法是:

available_songs = (LibraryEntry.objects.filter(player=activePlayer) 
              .filter(bannedsong__isnull = True)) 
+0

我之前试过这个,它不起作用。 Django比较每个集合的id字段。我想让它比较LibraryEntry集的id字段和banned_songs集的lib_id字段。不要将ID与ID进行比较。 – 2012-04-16 23:22:13

+0

@KurtisNusbaum我写道,在我意识到'banned_songs'是一个来自不同模型的查询集,而不是同一个模型。我更新它使用'values_list'。 – agf 2012-04-16 23:25:25

+0

太棒了。实际上这应该工作得很好。尽管在banned_songs很大的情况下,我担心一些性能问题。但就像我说的,我并不认为它很大。如果我把它变成一个OneToOneField而不是一个外键,那会改变什么吗? – 2012-04-16 23:27:27