Extending parent blocks from included template, looking for a workaround - python

I have a site with some ajax pages. If user types in a browser /login/, he should get a full rendered template, extended from a base template. But if user clicks a login button, $('#content').ajax('/login/'); called, so i don't need to render a full template.
I.e. i have this (login_ajax.html):
{% load i18n %}
{% block title %}
{% trans "Login" %}
{% endblock %}
{% block content %}
{% include "social.html" %}
{% endblock %}
In login.html:
{% extends "base.html" %}
{% block ajax_content %}
{% include "login_ajax.html" %}
{% endblock %}
Simple login view:
def login(request):
c = Context({'user': request.user})
if request.is_ajax():
return render_to_response('login_ajax.html', c, context_instance=RequestContext(request))
return render_to_response('login.html', c, context_instance=RequestContext(request))
This problem refers to documentation of include tag:
The include tag should be considered as an implementation of “render
this subtemplate and include the HTML”, not as “parse this subtemplate
and include its contents as if it were part of the parent”. This means
that there is no shared state between included templates – each
include is a completely independent rendering process.
But i don't want to place title name in a view, or place it twice in login.html and login_ajax.html also.

I think you need to move {% block title %} back out into login.html then make two ajax calls. One to override {% block ajax_content %} and one to override {% block title %}. You could use the same pattern for overriding {% block title %} as you've used for overriding {% block ajax_content %}, but you'd probably manage without actually creating a new title.html template.
I can't see any other way round your problem.

Ok, i've found a simple solution. In fact, the problem is in question: "to extend from base, or not to extend".
In fact, i don't care a template from what login.html should be extended. So, for ajax request, the parent template will be empty.html, and for default request, it will be base.html. So, i'll point a parent template in the view:
def login(request):
c = Context({'user': request.user, 'extends': 'empty.html'})
if request.is_ajax():
return render_to_response('login.html', c, context_instance=RequestContext(request))
c['extends'] = 'base.html'
return render_to_response('login.html', c, context_instance=RequestContext(request))
The empty.html just contain a placeholder for a block:
{% block content %}{% endblock %}
And here is login.html:
{% extends extends %}
{% load i18n %}
{% if extends != 'empty.html' %}
{% block title %}{% trans "Login" %}{% endblock %}
{% else %}
<div style="display: none;" class="ajax-title">{% trans "Login" %}</div>
{% endif %}
{% block content %}
{% include "social.html" %}
{% endblock %}
Also, i suppose, there is a way to turn login.html into a snippet, that could be included using with. i.e. {% include 'snippet.html' with extends='base.html' %}

Related

Passing a variable to include in extends in Django templates

I have the following structure of templates:
main.html
<html>
<body>
<p>
This works: {% block title %}{% endblock %}
</p>
{% include 'heading.html' with title=title %} {# but this does not work since it is not a variable #}
</body>
</html>
heading.html
<p>
{{ title }}
</p>
page.html
{% extends 'main.html' %}
{% block title %}test title{% endblock %}
How can I pass the title from page.html to heading.html? Ideally, it should be defined as a block like now, but alternatives are also welcome. I'd like to contain the solution within the templates if possible.
Clarification:
This is a minimal example, but I have multiple pages like main.html that share a larger header that has title and some other variables that I'd like defined in the child template (not necessarily as variable as long as the text is passed).
I could put the title into the view code, but this solution would just decrease the separation of displayed data from the logic.
Use a block around the include with variables, and then wrap {{ block.super }} in the with template tag.
main.html:
<html>
<body>
<p>
This works: {% block title %}{% endblock %}
</p>
{% block with_variables %}
{% include 'heading.html' %}
{% endblock %}
</body>
</html>
page.html:
{% extends 'main.html' %}
{% block title %}test title{% endblock %}
{% block with_variables %}
{% with title="variable title" %}
{{ block.super }}
{% endwith %}
{% endblock %}
You may name it {% block heading %}, or nest the whole main.html in {% block content %}.
instead of {% include %}, you might want to use custom template tags with returning html or extension like slippers
You don't need heading.html. You can use the context variable title directly; as long as you pass it to your render function in your view, e.g.:
views.py
def my_view(request):
context = {'title': 'Hello World!'}
return render(request, 'page.html', context=context)
main.html
<html>
<body>
<p>
This is my title:
{% block title %}{% endblock %}
</p>
</body>
</html>
page.html
{% extends 'main.html' %}
{% block title %}
<strong>{{title}}</strong>
{% endblock %}
If you have administrative rights to your Django installation, an easy and elegant solution would be to switch your Django's template renderer to Jinja2 instead using django-jinja as a backend.
The main advantage of Jinja2 for the needs of this question is that it supports assignment of a block to a variable through block assignments. Since Jinja2 is inspired by the Django template language, your existing templates will need few modifications, if any.
With Jinja2 as a template renderer, you can set the title variable with a block of HTML content in the child template:
page.html
{% extends 'main.html' %}
{% set title %}test title{% endset %}
The title variable will then work in the shared template:
main.html
<html>
<body>
<p>
Main template works: {{ title }}
</p>
{% include 'heading.html' %}
</body>
</html>
And it will also work in the included template:
heading.html
<p>
Included template also works: {{ title }}
</p>
Demo: https://replit.com/#blhsing/AlarmedCleverDebugmonitor
One possible solution is to split heading.html into two and add a {% block %} in-between, but this is an ugly workaround that is prone to bugs with unclosed tags.
I am searching for a better alternative.
main.html
...
{% include 'heading1.html' %} {# containing <p> #}
{% block title %}{% endblock %}
{% include 'heading2.html' %} {# containing </p> #}
...
Additionally, if white spaces are important, there has to be no new line between includes and the block.
add your title to the rendering context and it will be visible in page, main and included heading.

Correct way of using JINJA template for title in flask

I am trying to use jinja for setting default title for page for that I am using
Home{% block title %}
{% endblock title %}</title>
now on some other page I need to use this block so there if I am using only -About is shown on the title
{% block title %}
-About
{% endblock title %}</title>
expected is Home-About
if I use blockextend whole home page is coming on about page which I don't way how can I correct
this
{% extends 'base.html' %}
{% block title %}
About
{% endblock title %}</title>
The way I would do the title is have something like this in your base.html file
{% if title %}
<title>Home - {{title}}</title>
{%else%}
<title>Home</title>
{%endif%}
And then for each of your routes when you render the template you can set a title, if no title is set then the title will just be Home.
For example
retrun render_template("about.html", title = "About")
Would give you the title "Home - About"
If you want to use your method of doing it, I think what you have done should work, but in the base.html file you can change {% endblock title %} to just
{%endblock%}, and do the same in the other html file. Maybe that will solve your issue?
I hope that helps, sorry if I have misunderstood what you wanted.
To achieve this, it is better to use jinja macros. here is how:
my_macros.html
{% macro render_title(arg1, arg2) %}
# write your jinja html here
{% endmacro%}
{% macro render_something(arg1, arg2) %}
# write your jinja html here
{% endmacro%}
Then in your html where you want to use the macro:
{% extends 'base.html' %}
{% from 'my_macros.html' import render_title %}
{% block content %}
{{ render_title("something", "something else") }}
# jinja html anywhere
{% endblock content %}

How to make Django Nested Templates for better SRP

I'm attempting to make a base template for my website. Ideally it would look like this
{% block navigationbar %}{% endblock %}
{% block content %}{% endblock %}
{% block footer %}{% endblock %}
This way I am able to have separate navigationbar.html and footer.html files. All views I would like to show would then just put this:
{% extends 'portfolio/base.html' %}
{% block content %}
// View Code here
{% endblock %}
Any way to achieve this. I have realized I can't do multiple extends and I've tried different combinations of nesting but nothing has worked for me so far.
So the ideal result would be 4 files. for the homepage:
NavigationBar.html - Holds the navigation bar code
Footer.html - Holds the footer code
Base.html - Holds the navigation bar, footer, and content
Home.html - Holds the content of the home page, but when it loads the user sees the navigationbar, and footer as well.
You can use include that loads a template and renders it with the current context. This is a way of “including” other templates within a template.
This example includes the contents of the template "NavigationBar.html" and "Footer.html" on your template:
{% extends 'portfolio/base.html' %}
{% block content %}
{% include "NavigationBar.html" %}
// View Code here
{% include "Footer.html" %}
{% endblock %}
You can also pass additional context to the template using arguments:
{% include "NavigationBar.html" with breadcrumb="home > wherever" %}

Python template include a page if condition

i'm developing a small app with Python and Google app engine. I'm using boilerplate (https://github.com/coto/gae-boilerplate) as front-end which follows gae direction and python templates, so nothing diffrent than plain stuff.
Now, what i would like to have is this.
When a user logged in, if the field of name and last name are not filled in i would like to have, in the home page, the profile editing.
The page for editing the profile is a template (which extend the base.html), called edit_profile.html which works well.
The homepage is a template as well (extend the base.html) called home.html.
Now, can i include the edit_profile.html in home.html? how can i do it?
this is what i've, i don't know what to put instead of ???? i tried with
{% block edit_profile.html %} {% endblock %}
but does not work
{% if user_info.name and user_info.last_name %}
..
{% else %}
????
{% endif %}
thanks.
So you want to include only some block of given template. There are two solutions:
1) Create template just for profile editing form and include it into edit_profile.html. Then include it also into home.html to if condition branch:
profile_form.html:
<form action="{% url some-action %}">
{{ form }}
<input type="submit" value="save"/>
</form
profile_edit.html
{% extends "base.html" %}
{% block main %}
{% include "profile_form.html" %}
{% endblock %}
home.html
{% if user_info.name and user_info.last_name %}
{% include "profile_form.html" %}
{% endif %}
2) use variable for extended template:
profile_form.html
{% extend BASE_TEMPLATE %}
and set it into context w/ different value as needed:
in home.html (let's say included_form.html is some basic template)
{% if user_info.name and user_info.last_name %}
{% with "included_form.html" as BASE_TEMPLATE %}
{% include "edit_profile.html" %}
{% endwith %}
{% endif %}
and if you want show form as a standalone page, set BASE_TEMPLATE to base.html

Nested django templates

This seems like a pretty basic thing to do but although I've been using Django for around a year, I've never run into this scenario yet.
In a lot of templating/web frameworks, template inheritance works a bit differently, in that usually it behaves more like wrappers, so if you have childtemplate.html, parenttemplate.html, and grandparenttemplate.html, then the finally rendering usually looks something like:
grandparent header
parent header
child header
child content
parent content
parent footer
grandparent content
grandparent footer
That's not exactly how it works in Django but I'm wondering how to implement it.
Specifically I have my "child" template, let's just say it's foo.html. foo.html optional gets a variable parent_template or defaults to "base.html"
{% extends parent_template|default:"base.html" %}
{% block content %}
I am a foo and my title is {{ foo.title }}
{% endblock content %}
So, this is where I run into a snag. If parent_template is a template, that template should wrap the contents of foo.html and then place the result into base.html:
{% extends "base.html" %}
{% something_magical_here %}
<div>parent header</div>
# content of foo.html
<div>parent footer</div>
{% end_something_magical_here %}
And then in base.html:
<html>
... snip ...
<div id="content">
{% something_else_magical %}
# content of parent_template rendering, or just foo.html if no parent_template given
{% end_something_else_magical %}
Which should render as
<html>
... snip ...
<div id="content">
<div>parent header</div>
I am a foo and my title is Bar
<div>parent footer</div>
if parent_template is set and
<html>
... snip ...
<div id="content">
I am a foo and my title is Bar
if it is not.
I hope my problem is clear: I need to (optionally) wrap a template in a parent template, and then send the results of that to the base.html template.
Normally, something like this might work:
#foo.html
{% extends "parent.html" %}
{% block child_content %}
I am a foo and my title is {{ foo.title }}
{% endblock child_content %}
#parent.html
{% extends "base.html" %}
{% block content %}
parent header
{% block child_content %}{% endblock child_content %}
parent content
parent footer
#base.html
base header
{% block content %}{% endblock content %}
base content
base footer
However, since the parent_template could be blank, then sometimes base.html will be getting just the child_content block, not the content block.
Also, I'd like to be able to do this without having to create a bunch of sub-blocks (what if I decide that the foo application should have its own /foo/base.html that then calls /base.html)?
Any ideas?
the extends template tag can take a variable argument.
so:
base.html
{% block content %}
<p>BASE</p>
{% endblock %}
parent.html
{% extends "base.html" %}
{% block content %}
{{ block.super }}
<p>PARENT</p>
{% endblock %}
foo.html
{% extends ext_templ %}
{% block content %}
{{ block.super }}
<p>FOO</p>
{% endblock %}
using base:
return render_to_response('foo.html', {'ext_templ':'base.html'})
gives you:
<p>BASE</p>
<p>FOO</p>
using parent:
return render_to_response('foo.html', {'ext_templ':'parent.html'})
gives you:
<p>BASE</p>
<p>PARENT</p>
<p>FOO</p>
edit:
one way around this problem to get nested blocks is:
base.html
{% block content %}
{% block top %}
<p>BASE START</p>
{% endblock %}
{% block bot %}
<p>BASE END</p>
{% endblock %}
{% endblock %}
parent.html
{% extends "base.html" %}
{% block top %}
{{ block.super }}
<p>PARENT</p>
{% endblock %}
{% block bot %}
<p>PARENT</p>
{{ block.super }}
{% endblock %}
foo.html
{% extends ext_templ %}
{% block top %}
{{ block.super }}
<p>FOO</p>
{% endblock %}
{% block bot %}
<p>FOO END</p>
{{ block.super }}
{% endblock %}
The other method that i can think of is to wrap the blocks with an {% if ext_templ == 'parent.html' %} tag but that doesn't seem very dry. I'm curious to see other peoples response to nested blocks as well.
base.html
{% block content %}
<p>Grand Parent file</p>
{% endblock %}
parent.html
{% extends 'base.html' %}
{% block content %}
{% include 'grandchild1.html' %}
{% include 'grandchild2.html' %}
{% endblock %}
3.1. grandchild1.html
<div>Hello I'm grandchild 1</div>
3.2 grandchild1.html
<div>Hello I'm grandchild 2</div>
This way you can nest upto any level. write each components in sections in seperate .html files.
Include them to parent.html or to any other files.
I had three templates: gparent, parent, and gchild. Then I tested gparent and gchild as follows:
gparent had the following block hn tag. gchild extends gparent. There is no reference to parent.
{% block hn %}
Can you see me? # 1 naked text in the html, treated as a string.
{{ "No, I cant see you." }} # 2 A string literal in the variable template brace.
{% endblock hn %}
Both of these lines between the tags showed up on the child on screen. When the latter was not a string, Django threw a parsing error. That is because inside the double curly braces, Django is expecting a variable, or something like this string literal that it can evaluate.
When I added a block hn and this content to gchild, gchild's block hn content is all I saw.
{% block hn %}
Now I have my own hn block
{% endblock hn %}
Then I repeated this test, leaving gchild’s block hn in place, but taking away the content:
{% block hn %}
{% endblock hn %}
An empty, but present block hn on gchild blocked out (overrode) gparent's block hn content.
For this next test, I inserted parent between gparent and gchild. Now parent extends gparent, and gchild extends parent.
{% block metadata %}
{{ "You must eat your metadata to grow big and strong" }}
{% endblock metadata %}
Parent now has this block metadata tag, which is present in neither gparent nor gchild.
This content did not display.
Next I nested block metadata inside block hn on parent. gparent still has the two strings we tested from block hn a moment ago. gchild has an empty block hn.
As before, nothing displayed.
I will now remove block hn from gchild:
You must eat your metadata to grow big and strong
So, you can add a new block tag that is not present in an earlier template generation, so long as it is fully nested within an available block that the ancestor does define.
The sandwich generation will then pass that new tag and its content along to the child, which will display it if the child does not block (override) it.
Remember that the docs describe the content between the tags as a hole to be filled. If the child does not have the tag, the hole gets filled by the parent. This is what makes the parent’s content the default. This is also why most base templates contain the header, footer, navigation, and styling you want throughout the site. But with the same tag on the child, the child is filling the hole itself. Again, this is why a child can have its own block title tag, even though it is nested inside the html , which is typically inside the parent block header, or whatever you choose to call it.
I really struggled with this when I first learned Django, because I always wanted to do crazy stuff like
{% block first %}
{% block second %}
{% endblock first %}
{% endblock second %}
That will not work anywhere.

Categories

Resources