7

I have two blocks that call the same method with same variables. I want to call the method only once, but the result is then outsite the scope of the block tags. I've tried calling this method in the parent template header.html and with a with tag, but nothing seems to work.

This is the layout:

{% extends "header.html" %}
{% load navigation_tags %}
{% block header %}
 {% get_section site=site as section %}
 {% include "foobar.html" with section=section %}
{% endblock header %}
{% block navigation %}
 <nav>
 <div class="container">
 {% get_section site=site as section %}
 {% navigation section.slug %}
 </div>
 </nav>
{% endblock navigation %}

navigation_tags.py

@register.assignment_tag
def get_parent_section(site):
 if site.id == settings.FOOBAR_SITE_ID:
 section = Section.objects.get(id=settings.FOOBAR_SECTION_ID)
 else:
 # This is also a section instance.
 return site.default_section
asked Jul 16, 2018 at 12:52
7
  • Might be a good idea to include the code for get_section as well.... Also if it isn't an expensive call it might be easier to just do it twice Commented Jul 16, 2018 at 13:08
  • @ResleyRodrigues question updated. Commented Jul 16, 2018 at 13:18
  • 2
    Could it be because you don't return anything in the if condition? Commented Jul 16, 2018 at 13:51
  • @ResleyRodrigues good pointing out, forgot about that. However, this isnt the issue. The return value is still out of scope. Commented Jul 17, 2018 at 8:17
  • 4
    Since it's the same template, can't you include the section info in the context being injected there by the view? Commented Jul 20, 2018 at 13:33

2 Answers 2

2
+50

As mentioned by 2pacho in another answer and Fernando Cezar in a comment, the easiest way to share values between different sections is to set it in the template context. If you are using the render shortcut function, you can pass a dict as the context parameter to add a value to the rendering context of the template. That would be a good place to add it and this would be the easiest place to put it.

return render(request, 'template.html', {'section': get_parent_section(site)})

However, if for some reason, you can't include it in the context, you can use a decorator to add memoization to your function, so that it will cache the computation results and return it immediately when called with the same parameters. You can use functools.lru_cache to do so, or it's Django backport at django.utils.lru_cache.lru_cache if you are using Python 2.x.

@register.assignment_tag
@functools.lru_cache()
def get_parent_section(site):
 if site.id == settings.FOOBAR_SITE_ID:
 section = Section.objects.get(id=settings.FOOBAR_SECTION_ID)
 else:
 # This is also a section instance.
 return site.default_section
answered Jul 24, 2018 at 19:16
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. I knew I could just set it in context in views, but I wanted to know if there was something I could do on template level. This works fine.
Understood. Django's template are designed to be limited in what they can do, so I've found that the solution is usually to look outside of them.
0

I wouldn't call a method outside .py . Think that this is using Jinja2 templates, it's powerful but not in the way that the backend can be.

What I recommend you doing in this case is to generate a context for the template and use this variables there.

Would be as simple as adding it to your context where it's being generated.

context['site_parent'] = get_parent_section(site)

Think that Jinja2 (html) has to be as simple as possible and that can help you with basic coding and time saving (like loops to print the exact same information or show and hide code depending on the context) but I would keep it as simple you can when rendering.

If you would like you can read official django website about templates https://docs.djangoproject.com/en/2.0/topics/templates/

But from my expirience I would keep the method calls in the views.py

answered Jul 22, 2018 at 21:09

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.