Django and how to check if object has children - django

as a very much of a newbie in Django/python world I fail to find a way to check whether an object has children.
An example:
Class MyItems
title = models.CharField(max_length=50)
parent = models.ForeignKey('self',null=True, blank=True,related_name='subitems')
Then in my template:
{% for item in MyItems %}
<li> {{ item.title }} </li>
{% if item **IS A PARENT OF CHILDREN** %}
<p>This is what I want</p>
{% endif %}
{% endfor %}
I can see if an item has a parent no problem, but how to do it other way around, tell if an item is a parent to other item?
Thanks!

if you want a recursive parent child relationship between your objects you should look at using MPTT
http://django-mptt.github.com/django-mptt/
<ul class="root">
{% recursetree nodes %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
talked about in the cookbook here:
https://code.djangoproject.com/wiki/ModifiedPreorderTreeTraversal
to understand how MPTT works at a data level, have a look at http://en.wikipedia.org/wiki/Nested_set_model
The problem with the obvious solution, is that for each additional level children, another query is required - which gets extremely inefficient.
# this is an additional query AND will not be recursive.
{% if item.child_set.all.count > 0 %}

If I understood the question correctly, it should be as simple as this:
{% if item.subitems.exists %}

Related

How to Create a Mezzanine menu including children elements of current page

I want to create a Menu that handles information about the current page and their siblings for example, if I have the following tree:
If I am in page Child 1 my menu should only display Page 1 and the children 1-3
This can be achieved with the following code:
{{ page.parent.title }}
<ul>
{% page_menu page.parent %}
</ul>
The problem I have is that I would like to display the Grand Child 1 and 2 if I am located in Child 2. How can I do that?
I tried the following:
<ul>
{% for page in branch_page %}
{% if page.is_current_sibling %}
<li> {{ page.title }}
{% if page.is_current_or_ascendant %}
{% page_menu page %}
{% endif %}
{% endif %}
{% endfor %}
</ul>
But it doesn't work and it does not display any error, how can I do this in another way?
The page_menu template tag lets you pass in an optional parent page, and a menu template that will be used recursively for rendering children, eg where "page" is the current page:
{% load pages_tags %}
{% page_menu page "pages/menus/tree.html" %}
ref: https://groups.google.com/forum/#!msg/mezzanine-users/Fk2Nm6K6qho/VyePF5D6CXgJ

Cumulative count in recoursetree?

Using django-mppt I want to browse my category hierarchy displaying the ammount of objects related to the current category in any of it's children.
Much like drill_down_for_node in the example shown, but only with the current node childrens...
The optimal would be
{% recursetree obj.get_children cumulative count model.Foreignkey.category in o_count%}
<li>
<h2>{{ node }}</h2>
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }} ({{o_count}})
</ul>
{% endif %}
</li>
{% endrecursetree %}
Any pointers?
Found a function for this on the TreeManager:
https://github.com/django-mptt/django-mptt/blob/master/mptt/managers.py#L250
Add the counts to the queryset in your view:
context['qs_with_related_count'] = model1.objects.add_related_count(
obj.get_children(),
model2,
'category',
'o_count',
True
)
and in template:
{% recursetree qs_with_related_count %}
<li>
<h2>{{ node }} ({{ node.o_count }})</h2>
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
Unfortunately I was trying to use a ManyToManyField as rel_field:
https://github.com/django-mptt/django-mptt/issues/90
but it looks like you are in luck ('category' not 'categories') :)

Django template and splitting the variable list

In my django view, I pass a list that contains several items.
My html design is like this:
<ul>
<li>
<div>1st item</div>
<div>2nd item</div>
</li>
<li>
<div>3th item</div>
<div>4th item</div>
</li>
<li>
<div>5th item</div>
<div>6th item</div>
</li>
</ul>
You see the pattern, every two items, I need to split them and put into a new <li></li>. How can I loop and divide these variables by every two using {% for item in my_list %}?
You could try something like this which isn't particularly elegant and isn't tested in any way!
{% if list_of_items %}
<ul>
<li>
{% for item in list_of_items %}
<div>{{ item }}</div>
{% cycle '' '</li><li>' %}
{% endfor %}
</li>
</ul>
{% endif %}
You could re-arrange the list in your view first to make it a list of lists, or alternatively you could write your own batch filter.
As far as I know there isn't a really easy django template way of doing what you want - Django templates are deliberately restrictive to encourage you to write python code instead.
If the items have some property that groups them naturally into pairs, you can use regroup:
{% if list_of_items %}
<ul>
{% regroup list_of_items by property as item_chunks %}
{% for chunk in item_chunks %}
<li>
{% for item in chunk.list %}
{{ item }}
{% endfor %}
</li>
{% endfor %}
</ul>
{% endif %}
It's a couple more lines than Nick's solution, but if those elements do have a property that joins them naturally, I would say that this is a more elegant solution.
you might want to enumerate your total list of 6 elements in batches of size 2 which gives you 3 batches and then loop through each batch.
To do this, you can add a custom batch filter in your templatetags directory. Here is the documentation for adding custom tag/filter.
https://docs.djangoproject.com/en/1.9/howto/custom-template-tags/
Your custom filter can be something like this.
#register.filter
def batch(iterable, n=1):
l = len(iterable)
for ndx in range(0, l, n):
yield iterable[ndx:min(ndx + n, l)]
In your html
{% for batch in yourlist|batch:2%}
<li>
{% for element in batch %}
<div>{{element}}</div>
{% endfor %}
</li>
{% endfor %}
Updating this answer for Django 3.1
{% block content %}
<div class="row">
{% for product in products %}
<div class="col-md-auto">
<h5>{{ product.name }}</h5>
</div>
{% if forloop.counter|divisibleby:"6" %}
</div>
<div class="row">
{% endif %}
{% endfor %}
</div>
{% endblock content %}

show children nodes depending on selected parent

Hi i've been looking all over and can't find the answer to this. I have only 3 months experience in using python/django so excuse my dummy quesion!
Im using django mptt to display a simple nested set navigation.
<ul class="root">
{% recursetree nodes %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
this works fine - however i would like to show only children of the selected category (based on slug) and not all of them.
Any ideas ???
i finally did it like this:
{% recursetree nodes %}
<li>
<a href='/{{ node.get_absolute_url}}'>{{ node.name }}</a>
</li>
{% if not node.is_leaf.node %}
{% for c in child %}
{% if c in node.get_children %}
{% if forloop.first %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endrecursetree %}
in views
category = get_object_or_404(Category, slug=slug)
child = category.get_children()
if not child :
child = category.get_siblings()
but it is a hack. has anyone got better idea?
You need to send down some information about what node you're in, and then it's a simple if statement.
Regarding how to send down the node information universally, there are a couple ways to do this in Django, and none of them are perfect. My preferred method is context processors: http://docs.djangoproject.com/en/1.3/ref/templates/api/#writing-your-own-context-processors
{% recursetree nodes %}
<li>
{{ node.name }}
{% if node.name == category.name %}
<ul>
{{ children }}
</ul>
{% endif %}
<li>
{% endrecursetree %}
You can try this:
{% recursetree nodes %}
#check if the node is a child node
{% if node.is_child_node %}
<a href="{{ node.get_absolute_url }}" >{{ node.name }}</a>
{% endif %}
#check if a root node is the current category
{% if node.is_root_node and node.name == category.name %}
{{ children }}
{% endif %}
{% endrecursetree %}

Nested dictionaries and Django template

When there is a dictionary:
menu = {'title': 'Link1',
'children': {'title': 'Child of Link1',
'children': #etc..}
}
How would one iterate over it so that the output becomes:
<ul>
<li>Link1
<ul>
<li>Child of Link 1
<ul>
<li>Grandchild of Link 1
<ul>etc..</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
Currently I use this, but it obviously only goes to a depth of one.
<ul id="mainnavigation">
{% for k,v in admin.items %} #ContextProcessor, because this menu needs to know the current path.
<li class="expandable">{{ v.title }}
{% if v.children != None %}
<ul>
{% for id,child in v.children.items %}
<li class="expandable">{{ child.title }}</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
One way would be to manually repeat the loop for each level, however such a solution is ugly and I am hoping there is a more DRY one.
You'll have to make custom template tag for this. I would choose inclusion tag.
{% for k,v in var %}
{% my_tag v.children %}
{% endfor %}
If you already know that every part is just going to have title & children for each, why not just do nested tuples? You can then just use the built in filter, unordered_list.
So, it'd be:
menu = (Link 1 (Child of Link 1 (Grandchild of Link 1 (...) )))
and
<ul id="mainnavigation">
{{ menu|unordered_list }}
</ul>