2017-11-01 1 views
0

Ich habe eine Baumstruktur für Kategorien. Kategorien mit einem Fremdschlüssel, der sich auf sich selbst bezieht.Baumstruktur (Fremdschlüssel zu sich selbst) und Vorlagen

class Category(MetaData): 
    parent = models.ForeignKey('self', blank=True, null=True, verbose_name='parent category', on_delete=models.CASCADE) 
    name = models.CharField(max_length=255) 
    description = models.TextField() 

Weil ich weiß nicht, die Tiefe des Baumes Kategorie (für nicht verwenden) Ich brauche eine rekursive Funktion zu verwenden:

def cat_for_parents(self, cat_obj): 
       ... 
       if cat_obj.parent_id: 
         p = cat_obj.parent 
         ... 
         self.cat_for_parents(p) 

Aber wie ich die Funktion in der Vorlage implementieren zu bekommen so etwas wie diese (theoretisch unendlich rekursive Schleife):

<ul> 
<li>CategoryA 
    <ul> 
    <li>SubCategA1 
    <ul> 
     <li> Subcateg Subcateg B1 
     <ul> 
      <li> Subcateg SubCateg C1> 
      <li> Subcateg SubCateg C2> 
     <ul> 
     <li> Subcateg Subcateg B2> 
     ............. 
+2

Sie in mit aussehen sollte [django-MPTT] (https://github.com/django-mptt/django-mptt) für diese; Es enthält sowohl Datenbankstrukturen zum effizienten Speichern und Abrufen von Baumdaten als auch Schablonen-Tags zum rekursiven Rendern. –

+0

@Daniel Roseman - danke ich werde ihren Code überprüfen; Ich bevorzuge es, meine eigenen Sachen zu machen, wo und wie ich gebraucht habe, einschließlich der Django-Version, anstatt in diesem Fall einen Drittanbieter zu verwenden – user3541631

Antwort

1

I verwendet inclusion_tag dieses Problem zu lösen.

Beispiel:

model:

#just add related_name: 
parent = models.ForeignKey('self', blank=True, null=True, related_name='subs', on_delete=models.CASCADE) 

views.py:

categories = Category.objects.filter(parent=None) 
# then pass it to template 

template:

<ul> 
    {% for category in categories %} 
     <li> 
      {{ category.name }} 
      {% if category.parent.count > 0 %} 
       {% tree_structure category %} 
      {% endif %} 
     </li> 
    {% endfor %} 
</ul> 

Gewohnheit t ag Funktion:

@register.inclusion_tag('path/to/tree_structure.html') 
def tree_structure(category): 
    subs = category.subs.all() 
    return {"subs": subs} 

tree_structure.html:

# remember to load your custom tags file 
<ul> 
    {% for sub in subs %} 
     <li> 
      {{ sub.name }} 
      {% if sub.parent.count > 0 %} 
       {% tree_structure sub %} 
      {% endif %} 
     </li> 
    {% endfor %} 
</ul> 

Wie es funktioniert:

Getting die Kategorien ohne Eltern und senden Sie sie an Vorlage. In der Vorlage verwenden wir eine for-Schleife, um Kategorien nacheinander zu rendern. Bevor Sie in die nächste Kategorie zum Rendern gehen, prüfen Sie, ob diese Kategorie Subs enthält. Wenn für diese Kategorie Subs vorhanden waren, übergeben Sie die Kategorie an Ihr benutzerdefiniertes Template-Tag. Dort erhalten Sie alle Unterkategorien für diese Kategorie und übergeben diese an eine andere Vorlagendatei, um sie zu rendern, aber bevor Sie sie beenden, suchen Sie nach Diese Kategorie, um zu sehen, ob diese auch Unterkategorien hat oder nicht und wenn sie nur die benutzerdefinierte Funktion erneut aufruft, bevor Sie mit dem Rendern der ersten fertig sind. Es wird so lange gehen, bis es keine Kategorie und Unterkategorien mehr gibt, und am Ende wird eine vollständige Vorlage mit allen Unterkategorien für die erste übergebene Kategorie an die Hauptvorlage übergeben, die vor anderen Kategorien gerendert wird.

Ich konnte diesen Code nicht selbst testen, also könnte es kleine Probleme geben.

Überprüfen Sie auch die Dokumentation für eigenes Template tags: Custom template tags and filters