2012-04-16 145 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