2016-09-15 3 views
2

Ich habe ein Modell, das wie folgt aussieht:Wie rekursiv in Django rekursiv abfragen?

class StaffMember(models.Model): 

    id = models.OneToOneField(to=User, unique=True, primary_key=True, related_name='staff_member') 
    supervisor = models.ForeignKey(to='self', null=True, blank=True, related_name='team_members') 

Meine aktuelle Hierarchie der Mannschaft ist so ausgelegt, dass es ist ein Admin lassen sagen (die an der obersten Stelle der Hierarchie ist). Nehmen wir an, 3 Personen (A, B, C) melden sich beim Administrator und jeder von A, B und C hat sein eigenes Team, das ihnen Bericht erstattet usw.

Ich möchte alle Teammitglieder finden (bis auf die unterste Ebene der Hierarchie), für jeden Mitarbeiter. Meine aktuelle Methode, um alle Teammitglieder einer Person zu bekommen, ist wie:

def get_team(self): 
    team = [self] 
    for c in self.team_members.all(): 
     team += list(c.get_team()) 
     if len(team) > 2000: 
      break 
    return team 

ich die Teammitglieder eines Mitglieds erhalten von:

member = StaffMember.objects.get(pk=72) 
team = member.get_team() 

Aber offensichtlich, führt dies zu einer Menge von db Anrufe und meine API schließlich ausläuft. Was könnte effizienter sein, um alle Mitglieder eines Teams zu holen?

+0

uns zeigen Sie Ihre get_team() -Methode – sebb

+0

Es hat sich in der Frage hinzugefügt – Shubhanshu

+0

Haben Sie die _SET Methode auf Fremdschlüssel versucht, mit? Ich habe es noch nie mit einem rekursiven Modell gemacht, also weiß nicht, wie die Ausgabe aussehen könnte. Sie könnten auch versuchen .select_related() und sehen, was Sie am Ende haben. Ich denke, das wird Ihnen die notwendige Leistung geben, aber wie effizient ist ich mir nicht sicher. –

Antwort

1

Ich fand eine Lösung für das Problem. Die rekursive Lösung nimmt den Knoten, geht zu seinem ersten Kind und geht tief bis zum Ende der Hierarchie. Dann kommt wieder auf das zweite Kind zurück (falls vorhanden), und dann wieder runter bis zum Grund. Kurz gesagt, es erkundet alle Knoten nacheinander und hängt alle Mitglieder in einem Array an. Die Lösung, die ich mir ausgedacht habe, holt die Mitglieder schichtweise ab.

member = StaffMember.objects.get(id__id=user_id) 

new_list = [member] 

new_list = get_final_team(new_list) 

def get_final_team(qs): 
    team = [] 
    staffmembers = StaffMember.objects.filter(supervisor__in=qs) 

    team += staffmembers 
    if staffmembers: 
     interim_team_qs = get_final_team(staffmembers) 
     for qs in interim_team_qs: 
      team.append(qs) 
    else: 
     team = [qs] 

    return team 

Die Anzahl der db ruft diese Methode beinhaltet die Anzahl der Schichten (der Hierarchie), die unter dem Element vorhanden sind, dessen Team wollen wir herausfinden.

2

Wenn Sie eine Datenbank verwenden, die rekursive allgemeine Tabellenausdrücke unterstützt (z. B. PostgreSQL), ist dies genau der Anwendungsfall.

team = StaffMember.objects.raw(''' 
    WITH RECURSIVE team(id, supervisor) AS (
      SELECT id, supervisor 
      FROM staff_member 
      WHERE id = 42 
     UNION ALL 
      SELECT sm.id, sm.supervisor 
      FROM staff_member AS sm, team AS t 
      WHERE sm.id = t.supervisor 
     ) 
    SELECT * FROM team 
''') 

Referenzen: Raw SQL queries in Django
Recursive Common Table Expressions in PostgreSQL