Tomasz Brzezina
Tomasz Brzezina

Reputation: 1534

Nested variables in Django Templates

I'm not sure if it is variable or tag.

I have two apps (different styles, different navbars) but want to print the same document from db.

I created base.html, templates with extends and everything works perfectly. But.

The body of template is filled from database, which is a part of html code.

And in this code there's <p>The contact email is: [email protected]</p>

Of course this is wrong for secondapp.

I tried to change body with <p>The contact email is: {{ app_email }}</p>, and set it with context

But it doesn't work - it prints

The contact email is: {{ app_email }}

template/document.html:

{% extends base %}
{% load crispy_forms_tags %}
{% load static %}

{% block head %}
<title>{{ title }}</title>
{% endblock %}

{% block content %}
<div class="container">
    <div class="row justify-content-center">
       <div class="col-9">
           <h1 class="mt-2">{{ document.header }} !!!</h1>
          <hr class="mt-0 mb-4">
          {% autoescape off %}
          {{ document.body }}
          {% endautoescape %}
       </div>
     </div>
</div>
{% endblock %}

firstapp.views.py:

def myview(request):
    context = {
            'app_title' : 'First',
            'title' : 'First - document',
            'app_name' : 'first',
            'app_email' : '[email protected]',
            'document' : get_document('document1'),
            'base' : 'first/base.html'

secondapp.views.py:

def myview(request):
    context = {
            'app_title' : 'Second',
            'title' : 'Second - document',
            'app_name' : 'second',
            'app_email' : '[email protected]',

            'document' : get_document('document1'),
            'base' : 'second/base.html'

Is it possible this way? Mayby some filter?

edited: Now I know, that I have to prerender it in get_document. But how to pass unknown parameters?

This function works - but have to add sth do parameters (*args? **kwargs?) and redefine Context{{ *args? **kwargs?? }}

def get_document(name):
    doc = Doc.objects.get(name=name)
    doc.body = Template(doc.body).render(Context{{'app-email':'[email protected]'}})
    return doc

Upvotes: 0

Views: 638

Answers (2)

saquintes
saquintes

Reputation: 1089

The problem is you are treating the content of document1 in this case as a context variable itself. It never gets parsed by the django templating engine and so the {{ app_email }} variable is never converted.

I see two options:

  1. if the document is a file from disk (seems like that's not the case based on your description) then you need to figure out how to load the document into your template as another template. I know there are tags for loading another template based on the content of a variable. So you would pass template_name = "template/path/to/document" in your view and then in your template include it with something like {% include template_name %}. Actually, even if the template isn't on disk, you can write a template loader that loads it from where ever.

  2. Alternatively, you can send the results of get_document(...) through the template engine independently. So in the view.py you would render it separately before adding it to the template context. I think there used to be a django.shortcuts.render_string function you could pass it through, though I think that might have changed in newer Django's. Update from OP: Template(<str>).render(<context>) is the way to do it.

Upvotes: 2

Tomasz Brzezina
Tomasz Brzezina

Reputation: 1534

Thanks to @saquintes

def get_document(name,**kwargs):
    doc = Doc.objects.get(name=name)
    doc.body = Template(doc.body).render(Context(kwargs))
    return doc

and in first.views.py:

(...)

   def myview(request):
        context = {
            'app_title' : 'First',
            'title' : 'First - document',
            'app_name' : 'first',

            'document' : get_document('document1', app_email = '[email protected]'),
            'base' : 'first/base.html'

(...)

Upvotes: 0

Related Questions