2017-02-15 18 views
-1

У меня простая иерархическая модель, 3 черепахи высотой. Скажем, Artist, Album, Song. Что было бы эффективным способом фильтрации полученного дерева в моем представлении?Эффективный способ фильтрации иерархической структуры в Django?

Чтобы получить дерево Исполнитель/Альбом/Песня передать в шаблон, отфильтрованного с произвольным состоянием, я в настоящее время делать что-то вроде:

for current_artist in Artist.objects.filter(album__song__genre='funkadelic mariachi').distinct(): 
    yield current_artist 

    for current_album in Album.objects.filter(song__genre='funkadelic mariachi').distinct(): 
     yield current_album 

     for current_song in Song.objects.filter(genre='funkadelic mariachi'): 
      yield current_song 

     yield 'End of album' 
    yield 'End of artist' 

Но я почти уверен, что должно быть гораздо более эффективным способом, чем запрос на все пути к листьям на каждом уровне, если отдельные() и оптимизация Django не обеспечивают некоторый магический кеш с другой стороны радуги.

Возможно создание целого дерева (с любым художником и альбомом, не проверяя листья), а затем обрезание безлистных ветвей? Или я должен смотреть на select_related()?

За дополнительные баллы, некоторые фактические тесты/тесты/отзывы будут приветствоваться. Danke!

P.S: Я знаю о доброте django-mptt, но это слишком много для этого.

подробная модель не важна, так как я ищу общее решение, но это может быть что-то вроде:

class Artist: 
    name = models.CharField(max_length=200) 

class Album: 
    name = models.CharField(max_length=200) 
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE) 

class Song: 
    name = models.CharField(max_length=200) 
    album= models.ForeignKey(Album, on_delete=models.CASCADE) 
    genre = models.CharField(max_length=200) 
+0

Дерево «Исполнитель-альбом-песня» всех песен, которые соответствуют произвольному фильтру (я не только в funkadelic mariachis;). – Chema

+0

Модель состоит из трех классов: Artist, Album и Song. Думаю, их произвольные притязания не имеют значения. Я ищу простое общее решение. – Chema

ответ

0

Я закончил с следующим:

filters = { "genre": 'funkadelic mariachi' } 
artist = None 
album = None 
result = [] 

# select_related() fetches our chosen songs, and their albums and artists, in a single query 
for song in Song.objects.select_related(
     'album__artist').filter(**filters): 

    if album != song.album and album != None: 
     result.append('End of Album') 

    if artist != song.album.artist: 
     if artist != None: 
      result.append('End of Artist') 
     artist = song.album.artist 
     result.append(artist) 

    if album != song.album: 
     album = song.album 
     result.append(album) 

    result.append(song) 

if result: 
    result.append('End of Album') 
    result.append('End of Artist') 

Не так красиво, но гораздо эффективнее. Возможно, prefetch_related() позволит сохранить три петли, используя Prefetch ('artist', to_attr = 'filters_artists') или около того, но с одним дополнительным запросом на черепаху.

 Смежные вопросы

  • Нет связанных вопросов^_^