Django DRY - How to extend two .html files inside a Django Template? - html

What do I want?
I want to extend cards/apps.html inside addstudents.html so that I don't need to write the chucks of codes multiple times. What can I do to extends multiple .html files inside DJANGO template?
Error I am getting
'extends' cannot appear more than once in the same template
WHAT TO DO?
NOTE: I don't want to use {% include %}, because the situation/condition isn't suitable.
SOME INFORMATION YOU MAY NEED...
Inside cards/apps.html
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">{{card_title}}</h6>
</div>
<div class="card-body">
{% block card_body %}
{% endblock %}
</div>
Inside addstudents.html
{% extends 'layouts/panel.html' %}
{% extends 'apps/card.html' %}
{% load static %}
{% block content %}
{% with card_title='My Card TITLE' %}
{% block card_body %}
...SOME FORM, .... SOME PARAGRAPH
{% endblock %}
{% endblock %}
What's inside layouts/panel.html
layouts/panel.html contains some menu and navbars items [including CSS, bootstrap and JS dependencies].
What's apps/card.html?
apps/card.html contains the code-snippet of HTML and Bootstrap CARD. And I don't want to write this code multiple times. That's why I want it to be manipulated via Django Template Tags.
HOPE YOU UNDERSTOOD

I don't think this is directly possible. But here is a work around. In the view which handles addstudents.html, add has_card to the context as True.
views.py
def app_students(request):
# Your code
return render(request, 'addstudents.html', {'has_card': True})
layouts/panel.html
[...]
{% if has_card %}
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">{{card_title}}</h6>
</div>
<div class="card-body">
{% block card_body %}
{% endblock %}
</div>
</div>
{% endif %}
[...]
addstudents.html
{% extends 'layouts/panel.html' %}
{% with card_title='My Card TITLE' %}
{% block card_body %}
...SOME FORM, .... SOME PARAGRAPH
{% endblock %}
So this, if has_card doesn't exist, won't have the card_body block, but if it does exist as a truthy value, then it will.

I'm not sure if it fits your need.
One way could be to split the responsibilities a bit between the different templates.
From given information it could be possible to put bootstrap/layout stuff in cards/apps.html and add additional blocks for childs to override to just handle the forms and view specific information.
To clarify the inheritance that may resolve the problem:
layouts/panel.html -> apps/card.html -> addstudents.html
The apps/card.html overrides block content from layout/panel.html and adds additional blocks which are used by the addstudents.html.
It can also be seen as, in words: addstudents.html extends card.html which extends panel.html.
Afaik you can extend as many times you want, but not use extends twice in the same template.
cards/apps.html
{% extends 'layouts/panel.html' %}
{% block content %}
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">{% block card_title %}{% endblock %}</h6>
</div>
<div class="card-body">
{% block card_body %}
{% endblock %}
</div>
{% endblock content %}
addstudents.html
{% extends 'apps/card.html' %}
{% block card_title}My Card TITLE{% endblock card_title%}
{% block card_body %}
...SOME FORM, .... SOME PARAGRAPH
{% endblock card_body %}
Worth mention is also {{ block.super }} which can be quite useful sometimes if you need to render a "parent".

Related

Can header and footer be called from the base?

Currently my dilemma is I want the div in my base.html to be in my home_page.html but I need it around my header, main and footer.
This is my base.html
<div class="cover-container d-flex h-100 p-3 mx-auto flex-column">
{# header #}
{# /header #}
{% block content %}{% endblock %}
{# footer #}
{# footer #}
</div>
And this is my home_page that extends base.
{% extends "../base.html" %}
{% load static %}
{% load wagtailcore_tags wagtailimages_tags %}
{% block body_class %}Home{% endblock %}
{% block extra_css %}
{# Override this in templates to add extra stylesheets #}
{% endblock %}
{% block extra_js %}
{# Override this in templates to add extra javascript #}
{% endblock %}
{% block content %} {# html stuff sits in here#}
<main role="main" class="inner cover">
{% endblock %}
Is there a way to call on the header and footer specifically in the homepage.html?
I only want this div to be on the home page and not all the pages
I assume that what you mean here is that you only want this div to have this particular set of classes for the home page, and not for other pages (IOW, having a div with no classes or other classes is ok for the other pages).
If that's the case, the solution is simple: leave the div where it is, but wrap the div's classes into it's own block (with default - eventually empty - values), and override thsi block in the home page, ie:
base.html:
<div class="{% block page-css-class %}{% endblock %}">
{# header #}
{# /header #}
{% block content %}{% endblock %}
{# footer #}
{# footer #}
</div>
and home.html
{% extends "../base.html" %}
{% block page-css-class %}cover-container d-flex h-100 p-3 mx-auto flex-column{% endblock %}
{# your remaining code here #}
extends tag is used to inherit your parent template into the child template. It then looks for theblock tags in your parent template and replaces it with the values of the child template.
include tags loads a template and renders with the current context. You probably want to use {% include "footer.html" with my_context_variable=value %} to pass additional context.You can read more about it here.

Django - Generalising a Template with Optional Sidebar

I have a working solution for a template that allows for optional sidebars. Depending on the options selected by the user; significant DOM manipulations occur.
The working solution is unnecessarily large and features some code duplication. It also doesn't extend nicely.
I'm looking for a far more generic solution. One that allows for easier extending or abstracting so as to not have to repeat myself for every page that features a sidebar.
The Working Solution
{% extends "app/base.html" %}
{% load wagtailcore_tags %}
{% block content %}
{% if self.sidebar == "left" %}
<div class="row">
<div class="4u 12u(mobile)">
{% include "app/includes/sidebar.html" with sidebar_items=self.sidebar_items.all %}
</div>
<div class="8u 12u(mobile) important(mobile)">
<article class="box post">
{% include "app/includes/banner.html" with feed_image=self.feed_image only %}
{{ self.body|richtext }}
{% include "app/includes/related_links.html" with related_links=self.related_links.all only %}
</article>
</div>
</div>
{% elif self.sidebar == "right" %}
<div class="row">
<div class="8u 12u(mobile)">
<article class="box post">
{% include "app/includes/banner.html" with feed_image=self.feed_image only %}
{{ self.body|richtext }}
{% include "app/includes/related_links.html" with related_links=self.related_links.all only %}
</article>
</div>
<div class="4u 12u(mobile)">
{% include "app/includes/sidebar.html" with sidebar_items=self.sidebar_items.all %}
</div>
</div>
{% else %}
<article class="box post">
{% include "app/includes/banner.html" with feed_image=self.feed_image only %}
{{ self.body|richtext }}
{% include "app/includes/related_links.html" with related_links=self.related_links.all only %}
</article>
{% endif %}
{% endblock %}
{% block content %} is first defined here in app/base.html:
<div id="main-wrapper">
<div class="container">
<!-- <article class="box post"> -->
{% block content %}{% endblock %}
<!-- {% include 'app/includes/prev_next.html' %} -->
<!-- </article> -->
</div>
</div>
And sidebar.html looks like this:
{% load wagtailimages_tags %}
{% for sidebar_item in sidebar_items %}
<section class="box">
{% image sidebar_item.image original as img %}
<img src="{{ img.url }}" alt="" />
<header>
<h3>{{ sidebar_item.title }}</h3>
</header>
<p>{{ sidebar_item.body }}</p>
{% if sidebar_item.button_text %}
<footer>
{{ sidebar_item.button_text }}
</footer>
{% endif %}
</section>
{% endfor %}
My initial attempt at generalising it was to try to do all of the conditionals in app/base.html but I faced issues when it came to optionally the location of {{ block content }}.
Any help greatly appreciated.
If the condition to decide type of sidebar are being decided and supplied by the views.py function serving the page, then the best approach would be to simply make different template for each different page.
This solution sounds overly simple, but if correctly modularized(in terms of all the common code being kept in a basefile and being extended as and when needed), this would be the best approach. Even though the number of other templates might increase, it will give shorter load times because of smaller HTML snippets.
In case you do not want the conditional decisions being handled by views.py , you can alternatively use AJAX, and asynchronously change the template being viewed without causing a reload.
Hope this helps!

How to arrange content into grid view dynamically?

I want to arrange the following Figure1 content into horizon grid view, here content coming into vertical so, how to arrange into horizontal grid view, like Figure2
Figure1:
Figure2:
Here I only required the css class in div, Please tell the css class to arrange the grid into horizontal form.
Jinja2 Templates
_data_grid.html
This template, takes rows(number of data, like in the following Figure2 we have 5 data), and columns(Image Name, Type, Status, public, protected, Formate, size, Action), All these info comes from the database and django framework.
{% load i18n %}
{% with table.needs_form_wrapper as needs_form_wrapper %}
<div class="table_wrapper">
{% if needs_form_wrapper %}<form action="{{ table.get_full_url }}" method="POST">{% csrf_token %}{% endif %}
{% with columns=table.get_columns rows=table.get_rows %}
{% block grid %}
<grid id="{{table.slugify_name}}">
<div>
{% block grid_caption %}
<h3 class='table_title'>{{ table }}</h3>
{{ table.render_table_actions }}
{% endblock grid_caption %}
</div>
</br>
</br>
</br>
</br>
{% block grid_body %}
<div>
{% for row in rows %}
{{ row.render }}
{% empty %}
{{ table.get_empty_message }}
{% endfor %}
</div>
{% endblock grid_body %}
</grid>
{% endblock grid %}
{% endwith %}
{% if needs_form_wrapper %}</form>{% endif %}
</div>
{% endwith %}
_data_grid_cell.html
This template is used to fill the content,
{% if cell.inline_edit_mod and cell.update_allowed %}
{% else %}
{% if cell.inline_edit_available and cell.update_allowed %}
{% else %}
<ul>{{ cell.value }}</ul>
{% endif %}
{% endif %}
If you want to code the css your self flexbox will be what you are looking for. But I will be easier and probably cleaner to use css frameworks like Bootstrap, your code should look somthing like this, then you can add django template tags:
<div class="container">
<div class="row">
<div class="col-sm-4 col-md-4"><!--block 1--></div>
<div class="col-sm-4 col-md-4"><!--block 2--></div>
<div class="col-sm-4 col-md-4"><!--block 3--></div>
<div class="col-sm-4 col-md-4"><!--block 4--></div>
</div>
</div>
Check (Bootstrap Grid) for more details and explanation for the css classes.

multiple arbitrary blocks in Jinja2 macros

I use both Jinja2 and Nunjucks (depending on the project), but have yet to figure out how to create reusable elements with multiple blocks containing arbitrary HTML. For example (pseudo-code):
{% macro item(class) %}
<article class="{{ class }}">
<h3>{{ caller(1) }}</h3>
<p>{{ caller(2) }}</p>
</article>
{% endmacro %}
{% call item %}
Hello <abbr title="...">world</abbr>!
{% ---- %}
lorem <em>ipsum</em> dolor <strong>sit</strong> amet
{% endcall %}
Passing the respective blocks' HTML as regular arguments (i.e. strings) to the macro seems unrealistic.
A less contrived example might be Bootstrap-style forms:
<div class="form-group">
<label for="{{ id }}" class="control-label">$label</label>
<input type="{{ type }}" id="{{ id }}">
<p class="help-block">$hint</p>
</div>
Here both $label and $hint might be arbitrary blocks of HTML - perhaps there might even be multiple fields, defined outside the macro.
What's the recommended approach here?
You might find this useful for re-usable HTML components:
https://github.com/mozilla/nunjucks/pull/277
Example:
{% include 'search-box.html.twig' with {placeholder: 'Search users'} %}
You can use embed tag of atpl template engine.
Example:
{% embed "teasers_skeleton.twig" %}
{# These blocks are defined in "teasers_skeleton.twig" #}
{# and we override them right here: #}
{% block label %}
Some content for the label box
{% endblock %}
{% block hint %}
Some content for the hint box
{% endblock %}
{% endembed %}

jinja2: render template without extend

How I can render template without extend? i have simple renderer and i want after findout this request is ajax just render goal data
my template:
{% extends "base.html" %}
{% load i18n %}
{% block extrahead %}
{% endblock extrahead %}
{% block content %}
<div class="itemBg">
<div class="itemTop">
<div class="itemDown">
<div class="rowContainer">
<div class="show att">
{{ msg }}
</div>
</div>
</div></div></div>
{% endblock %}
only i want this in render response for ajax request.
<div class="itemBg">
<div class="itemTop">
<div class="itemDown">
<div class="rowContainer">
<div class="show att">
{{ msg }}
</div>
</div>
</div></div></div>
this is my render interface
from flask import current_app, render_template
def render(template, **context):
"""
"""
return render_template(path(template), **context)
You are looking for the null-master fallback trick. Since request is available in the Jinja2 context, if you are using a library that sets the appropriate header you can simply do this:
{% if not request.is_xhr %}{% extends "base.html" %}{% endif -%}
{% load i18n %}
{% block content %}
<div class="itemBg">
<div class="itemTop">
<div class="itemDown">
<div class="rowContainer">
<div class="show att">
{{ msg }}
</div>
</div>
</div></div></div>
{% endblock %}
Put the block you want for AJAX in a separate template.
When you get an AJAX request, just render that new template. For non-AJAX requests, include it in the one that extends base.html.