Last active
October 24, 2017 08:26
-
-
Save LowerDeez/caabff058372d7624a582de7c9ceeff0 to your computer and use it in GitHub Desktop.
Django-mptt. Getting recursive tree objects for jinja2 templates to avoid n+1 queries for children nodes when using translations fields in model(parler)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--Another jinja template for variant with cache categories--> | |
<ul class="categories"> | |
<li> | |
<form id="all_categories_form" action="{{ url('articles:home') }}" method="get"> | |
<input type="hidden" name="is_clear" value="True"> | |
<a href="#" onclick="document.getElementById('all_categories_form').submit();">All</a> | |
</form> | |
</li> | |
{% cache 150 "categories_tree" %} | |
<form action="" method="get" class="form-group"> | |
{% for node in categories recursive %} | |
{% set node_children = node.get_children() %} | |
{% if node.has_articles %} {# using to hide child categories, which have no articles #} | |
<li> | |
{% if node_children %} | |
<a class="category-dropdown" id="{{ node.id }}" type="button" | |
data-toggle="collapse" data-target="#category-{{ node.id }}"> | |
<span class="glyphicon glyphicon-chevron-right"></span> | |
</a> | |
{% endif %} | |
<input class="category-checkbox" id="category-check-{{ node.id }}" | |
type="checkbox" name="categories" value="{{ node.id }}"> | |
<a | |
{% if category %} | |
{% if node.slug == category.slug %} | |
class="selected" | |
{% endif %} | |
{% endif %} href="{{ node.get_absolute_url() }}" > | |
{{ node.name }} | |
</a> | |
</li> | |
{% endif %} | |
{% if node_children %} | |
<div id="category-{{ node.id }}" class="collapse"> | |
<ul class="children child-categories"> | |
{{ loop(node_children) }} | |
</ul> | |
</div> | |
{% endif %} | |
{% endfor %} | |
<button class="btn btn-success btn-category-search" type="submit">Find several categories</button> | |
</form> | |
{% endcache %} | |
</ul> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% load i18n %} | |
{% load mptt_tags %} | |
<ul class="categories"> | |
<li {% if not category %}class="selected"{% endif %}> | |
<a href="{% url 'articles:home' %}">{% trans "All" %}</a> | |
</li> | |
{% recursetree categories %} | |
<li {% if node.slug == category.slug %}class="selected"{% endif %}> | |
<a class="selected" href="{{ node.get_absolute_url }}">{{ node.name }}</a> | |
</li> | |
{% if not node.is_leaf_node %} | |
<ul class="children"> | |
{{ children }} | |
</ul> | |
{% endif %} | |
{% endrecursetree %} | |
</ul> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- Jinja template--> | |
<ul class="categories"> | |
<li {% if not category %}class="selected"{% endif %}> | |
<a href="{{ url('articles:home') }}">{{ _('All') }}</a> | |
</li> | |
{% for node in categories recursive %} | |
<li> | |
<a {% if category %} | |
{% if node.slug == category.slug %} | |
class="selected" | |
{% endif %} | |
{% endif %} href="{{ node.get_absolute_url() }}">{{ node.name }}</a> | |
</li> | |
{% if not node.is_leaf_node() %} | |
<ul class="children"> | |
{{ loop(node.get_children()) }} | |
</ul> | |
{% endif %} | |
{% endfor %} | |
</ul> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class YourListView(ListView): | |
def get_context_data(self, **kwargs): | |
# if you want to display all categories | |
categories = Category.objects.select_related('parent')\ | |
.prefetch_related('translations').get_cached_trees() | |
context['categories'] = categories | |
# cached categories but only with items, which related to some objects | |
categories = cache.get('{}-categories'.format(reverse('articles:home'))) | |
if categories: | |
prefetch_related_objects(categories, 'translations') | |
if not categories: | |
categories = Category.objects.with_articles() | |
# remove categories, which are children of another categories in queryset, | |
# because they will be rendering in template | |
for cat in categories: | |
categories = categories.exclude(id__in=cat.get_descendants()) | |
cache.set('{}-categories'.format(reverse('articles:home')), categories, CACHE_TTL) | |
context['categories'] = categories | |
# Method in category maneger, instead articles, you can have any model, which have TreeManyToManyField and related_name (articles in this case): | |
# Example: | |
# categories = TreeManyToManyField(Category, verbose_name=_("Categories"), blank=True, related_name='articles') | |
# def with_articles(self): | |
# return self.get_queryset().exclude(articles__isnull=True).select_related('parent').distinct() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment