16710

Tree Structure (Foreign Keys to itself) and templates

Question:

I have a tree structure for Categories. Categories with a Foreign key that is referring to itself.

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()

Because I don't know the depth of the categories tree(can't use for) I need to use a recursive function:

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

But how I implement the function in the template to get something like this(to theoretically infinite recursive loop):

<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> .............

Answer1:

I used inclusion_tag to solve this.

Example:

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>

Custom tag function:

@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>

How it works:

Getting the categories without any parent and send them to template. In template we use a for loop to render categories one by one and before going to next category to render, you check if that category hast any subs. If there was any subs for that category, you will pass the category to your custom template tag and there you will get all the sub categories for that given category and pass it to another template file to render them but before finishing it, check for that category to see if that one has sub categories too or not and if it does just call custom function again before u finish rendering the first one. it will goes till there is no more category and sub categories and at the end passes a complete template with all the sub categories for the first passed category to the main template to render before other categories.

I couldn't test this code myself so there might be small issues.

Also check the documentation for custom template tags: <a href="https://docs.djangoproject.com/en/1.11/howto/custom-template-tags/" rel="nofollow">Custom template tags and filters</a>

Recommend

  • WSO2 ESB Mediation Sequence vs Proxy Service
  • What is the benefit of update instead of doing delete and then Insert in the same table
  • Core data structure use multiple entities or not?
  • Sails.js associations
  • cakephp model association/join with same table [closed]
  • override relationship behaviour in sqlalchemy
  • Google Datastore - Not Seeing 1 Write per Second per Entity Group Limitation
  • infinite loop slider using keyframes css3
  • PostgreSQL: update with left outer self join ignored
  • Mongoose find() call inside for loop using a latch
  • Python: I fell in an infinite loop
  • How can I get rid of dynamic SQL
  • Wiring top-level DAGs together
  • MySQL table structure question
  • Wordpress Create Category AJAX Response
  • Jquery javascript: have a filtering list(works), need help keeping all LI's visible when there&
  • The model item passed into the dictionary is of type A, but this dictionary requires a model item of
  • YII - how we can get the name of the method in init() function in controller?
  • Querying multiple tables
  • How to resolve “ Multiplicity is not valid in Role” error?
  • Taking mean across rows grouped by a variable in numpy
  • Change navbar in bootstrap if user login
  • @tailrec why does this method not compile with 'contains a recursive call not in tail position&
  • Scanner nextInt() and hasNextInt() problems
  • Django foreign key drop down
  • Disable Kendo Autocomplete
  • Django invalid literal for int() with base 10
  • MS Access - How to change the linked table path by amend the table
  • Insert new calendar with SyncAdapter- Calendar API Android
  • xtable package: Skipping some rows in the output
  • Django simple Captcha “No module named fields” error
  • How to write order and limit within cakephp joins array
  • java inputstream
  • C++ Partial template specialization - design simplification
  • C# - Serializing and deserializing static member
  • Bug in WPF DataGrid
  • Incrementing object id automatically JS constructor (static method and variable)
  • KeystoneJS: Relationships in Admin UI not updating
  • trying to dynamically update Highchart column chart but series undefined
  • Observable and ngFor in Angular 2