Jinja2 Multi-level template inheritance issue - django

I have the following three files in a Django App, with the template engine being Jinja2
skeleton.html
<head>
{% block head_content %}
<meta charset="utf-8">
<title> {% if page_title %} {{ page_title }} | {% endif %} Bhargavi Books & Stationery </title>
<link rel="stylesheet" href="{{ static("css/semantic.min.css") }}">
<link rel="stylesheet" href="{{ static("Icons/font-awesome.min.css") }}">
{% endblock head_content %}
</head>
<body>
<div id="navigation">
{% block navigation %}
<div class="ui three item menu">
<a class="active item">Home</a>
<a class="item">New Bill</a>
<a class="item">View Bills</a>
</div>
{% endblock navigation %}
</div>
<div id="frame">
{% block frame_content %}
<p> Body content goes here. Body for {{ content_name }}</p>
{% endblock frame_content %}
</div>
<div id="app">
{% block app_content %}
<p> APP content goes here. Body for {{ content_name }}</p>
{% endblock app_content %}
</div>
{% block scripts %}
<script src="{{ static("js/jquery.js") }}"></script>
<script src=" {{ static("js/semantic.min.js") }} "></script>
{% endblock scripts %}
</body>
base.html
{% extends "skeleton.html" %}
{% from "macros/globalmacros.html" import
SUIIconList,SUISimpleList,
SUIImageLabel,SUILabel,
SUIActionInput,SUILabeledInput,SUIInput,
SUIDimmableActionCard,SUICard,
%}
{% block frame_content %}
Frame Content
{% endblock frame_content %}
{% block scripts %}
{{ super() }}
<script src=" {{ static("js/globalmacros.js") }} "></script>
{% endblock scripts %}
dashboard.html
{% extends "base.html" %}
<div>
{% block body_content %}
Body 3
{% endblock body_content %}
</div>
<div>
{% block app_content %}
DASHBOARD
{% endblock app_content %}
</div>
In this setup, Jinja renders everything except the "DASHBOARD" in the final page. However, when I add an empty block in "base.html", like so..
{% block app_content %}
App content Goes here...
{% endblock app_content %}
In the final template, "DASHBOARD" is printed. Is this some quirk in Jinja? Is this behavior defined in any docs??

I understand your issue: you've got template A, template B (extends template A), and template C (extends template B). There's a block defined in template A, but it's not showing up in the page that uses template C, unless you define that block in template B. If you do that, then the block in question shows up.
First: you are correct in your understanding that this is not how the Jinja template hierarchy is supposed to work. Second, I did not encounter your issue (found a different one, though), and I have constructed a proof to demonstrate this. Here's what I did (again, using Python 3 and Django 1.11):
$ python startproject myapp
In the myapp/myapp/settings.py file, I updated the template engine:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'DIRS': [
os.path.join(BASE_DIR, 'myapp/templates') # hack / should add `myapp` to INSTALLED_APPS instead
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
In myapp/myapp/urls.py, I created a dummy view function & route:
from django.conf.urls import url
from django.shortcuts import render_to_response
def home(request):
return render_to_response('dashboard.html')
urlpatterns = [
url(r'^$', home),
]
And finally, I established those templates, but I removed the call to import your macros, along with all instances of static().
Here is the myapp/myapp/templates/skeleton.html file:
<!doctype html>
<html lang="en">
<head>
{% block head_content %}
<meta charset="utf-8">
<title> {% if page_title %} {{ page_title }} | {% endif %} Bhargavi Books & Stationery </title>
{% endblock head_content %}
</head>
<body>
<div id="navigation">
{% block navigation %}
<div class="ui three item menu">
<a class="active item">Home</a>
<a class="item">New Bill</a>
<a class="item">View Bills</a>
</div>
{% endblock navigation %}
</div>
<div id="frame">
{% block frame_content %}
<p> Body content goes here. Body for {{ content_name }}</p>
{% endblock frame_content %}
</div>
<div id="app">
{% block app_content %}
<p> APP content goes here. Body for {{ content_name }}</p>
{% endblock app_content %}
</div>
{% block scripts %}
{% endblock scripts %}
</body>
</html>
Here is the myapp/myapp/base.html file:
{% extends "skeleton.html" %}
{% block frame_content %}
Frame Content
{% endblock frame_content %}
{% block scripts %}
{{ super() }}
{% endblock scripts %}
And here is the myapp/myapp/templates/dashboard.html file:
{% extends "base.html" %}
<div>
{% block body_content %}
Body 3
{% endblock body_content %}
</div>
<div>
{% block app_content %}
DASHBOARD
{% endblock app_content %}
</div>
And here is the output, after viewing that page in my browser:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> Bhargavi Books & Stationery </title>
</head>
<body>
<div id="navigation">
<div class="ui three item menu">
<a class="active item">Home</a>
<a class="item">New Bill</a>
<a class="item">View Bills</a>
</div>
</div>
<div id="frame">
Frame Content
</div>
<div id="app">
DASHBOARD
</div>
</body>
</html>
Since this all works as expected*, my conclusion is that you might have a problem with the base.html template file. Perhaps it's failing to import your macros, and subsequently not behaving correctly? I notice a trailing comma in there, and I'm not sure if that could be problematic or not. I would suggest using the above code as a starting point, and then slowly add back in the parts that I stripped out, and perhaps the problem will become visible/understandable.
*One thing I found odd, that I don't understand: the body_content block is completely missing from my output, unless I define that block in the skeleton.html template. It doesn't work if I define it in the base.html template, which seems wrong to me, because then we're not really extending that second template (base.html)... so there does seem to be something weird there... but I was not able to encounter the original issue you described, so maybe this will be helpful in that particular regards, at least.

Related

Django how to use blocks in templates

Basicly my django project consists of the templates with html.
I would like to fill the context of the site using blocks.
My problem is that I would like to send the block to sidebar and the base part of the page from application's .html files.
Templates:
sidebar.html
footer.html
header.html
base.html
In my base.html I use:
{% include 'partials/_sidebar.html' %}
{% block content %}{% endblock %}
in my sidebar.html I use
{% block sidebar %}{% endblock %}
and in my Application index.html i try to use:
{% extends 'base.html' %}
{% load static %}
{% block content %}
<h1>Home Page</h1>
{% endblock %}
{% block sidebar %}
<div class="bg-white py-2 collapse-inner rounded"></div>
<h6 class="collapse-header">Custom Components:</h6>
<a class="collapse-item" href="{% url 'veggies' %}">veggies</a>
<a class="collapse-item" href="{% url 'fruits' %}">fruits</a>
</div>
{% endblock %}
But it is obviously not working.
The starting page triggers app/index.html with a view.
How to workaround such a problem?
[i cant add post][1]
[1]: https://i.stack.imgur.com/FV3Co.png
Hopefully I can demonstrate how you use blocks by sharing some example templates with you.
Starting with a base template, that generally has the most content and contains the basic markup;
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{% block title %}{% endblock title %}</title>
<meta name="description" content="{% block meta_description %}{% endblock meta_description %}">
<meta name="viewport" content="width=device-width,initial-scale=1">
{% block styles %}{% endblock %}
{% block scripts %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/js-cookie/2.2.1/js.cookie.min.js"></script>
<script type="text/javascript" src="https://kit.fontawesome.com/c3c34cb042.js" crossorigin="anonymous"></script>
{% endblock %}
{% block head_extras %}{% endblock %}
</head>
<body>
{% block header %}{% endblock header %}
{% block content %}{% endblock content %}
{% block footer %}{% endblock footer %}
{% block footer_scripts %}
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
{% endblock %}
</body>
</html>
Then a page for content would extend that and you'd include in this template the blocks you want to add content to;
{% extends "base.html" %}
{% load static %}
{% block title %}Content Page{% endblock title %}
{% block content %}
<section class="">
<div class="container-fluid container-xl">
<div class="content-section">
<h1 class="content-section__heading-1">Content Page</h1>
<p>Hello World!</p>
</div>
</div>
</section>
{% endblock content %}
That'd be a really simple setup. But as you've said, you might also use the {% include %} tag.
What that does is inject the content of the included template into the template at the point you use the tag.
So in a template with a sidebar, that might look like;
{% extends "base.html" %}
{% load static %}
{% block title %}Sidebar Content Page{% endblock title %}
{% block content %}
<section class="">
<div class="container-fluid container-xl">
<div class="content-section">
<h1 class="content-section__heading-1">Content Page</h1>
<p>Hello World!</p>
</div>
{% include 'partials/_sidebar.html' %}
</div>
</section>
{% endblock content %}

Addind Datepicker_plus from bootstrap but button inactive

I add bootstrap_datepicker_plus to my code. In my template, I can see the calendar button on the right side of my field but when I click on the button nothing happened
try to modify settings, and template organization but nothing changes
Hi thanks for that. I still an issue, button on the right side to select date in the template is not working. I click on it but nothing..
this is the code modified:
in setting.py
# needed for using bootstrap_datepicker_plus
BOOTSTRAP3 = {
'include_jquery': True,
}
and add 'bootstrap_datepicker_plus', in installed apps
html file:
{% extends 'imports/base.html' %}
{% load bootstrap3 %}
<!-- necessaire pour date picker -->
{% block extra_css %}
{{ form.media.css }}
{% endblock %}
{% block extra_js %}
{{ form.media.js }}
{% endblock %}
<!-- Fin date picker -->
{% block title %}Imports Company{% endblock %}
{% block heading %}<h3 class="page-header-center">Creation Company</h3> {% endblock %}
<hr>
<hr>
{% block page %}
<form method="POST">
{% csrf_token %}
<div class="col-lg-4 col-md-4 col-sm-4 content">
{% bootstrap_form company_form %}
<button type="submit" class="btn btn-pink pull-right">Create</button>
</div>
</form>
{% endblock %}
imports/base.html:
{% load staticfiles %}
{% load bootstrap3 %} {# import bootstrap4/bootstrap3 #}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- Necessaire pour bootstrap datepicker -->
{% bootstrap_css %} {# Embed Bootstrap CSS #}
{% block extra_css %}
{{ form.media.css }}
{% endblock %}
<!-- fin du code boots trap datepicker -->
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<script src="{% static 'js/bootstrap.min.js' %}"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-lg-2 col-md-2 col-sm-2 sidebar">
{% block sidebar %}{% endblock %}
</div>
<div class="col-lg-10 col-lg-offset-2 col-md-10 col-md-offset-2 col-sm-10 col-sm-offset-2 content">
{% block heading %}{% endblock %}
{% block page %}{% endblock %}
</div>
</div>
</div>
<!-- Necessaire pour bootstrap datepicker -->
{% bootstrap_javascript jquery='full' %} {# Embed Bootstrap JS+jQuery #}
{% block extra_js %}
{{ form.media.js }}
{% endblock %}
<!-- fin du code boots trap datepicker -->
</body>
</html>
and
forms.py:
class CompanyForm(forms.ModelForm):
class Meta:
model = Company
fields = ("company_name", "fiscal_end_of_year")
widgets = {
'fiscal_end_of_year': DatePickerInput(), # default date-format %m/%d/%Y will be used
}
models.py:
class Company(models.Model):
company_id = models.IntegerField(default=170)
company_name = models.CharField(max_length=100, null=False)
fiscal_end_of_year = models.DateField()
I missed something but where :-) ?
Expects to see calendar when clicking on the button

Multiple Levels Of Inheritance Using Django Templates

I'm creating a Django project, where I want to use multiple levels of inheritance in my templates. E.g I want to do something like this:
project_base.html
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
<link href="{% static "css/bootstrap.min.css" %}" rel="stylesheet">
</head>
<body>
<div id="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
Then in app_base.html I extend this.
{% extends "project/project_base.html" %}
{% block title %}Generic Title{% endblock %}
{% block content %}
<img src="/dir/sub_dir/image.jpg">
{% block app_content %}
{% endblock %}
{% endblock %}
Finally I have my actual template
{% extends app_base.html %}
{% block title %}Specific Title{% endblock %}
{% block app_content %}
{% for obj in objects %}
{{ obj.name }}
{% endfor %}
{% endblock %}
The problem that I have is that when I go to load that page I see a single heading from an entirely unrelated template, and not my list of hyperlinks. What's the correct/best way to have multiple levels of inheritance for my template files?

How to set up a custom template in djangocms

I've successfully installed djangocms on a Ubuntu machine, and now I would like to integrate a custom template bought from Envato.
After I have installed it, djangocms came with its own simple template files which are located in mysite/templates:
base.html
{% load cms_tags staticfiles sekizai_tags menu_tags %}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>{% block title %}This is my new project home page{% endblock title %}</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap-theme.min.css">
{% render_block "css" %}
</head>
<body>
{% cms_toolbar %}
<div class="container">
<div class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
{% show_menu 0 1 100 100 "menu.html" %}
</ul>
</div>
</div>
{% block content %}{% endblock content %}
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js"></script>
{% render_block "js" %}
</body>
</html>
feature.html
{% extends "base.html" %}
{% load cms_tags %}
{% block title %}{% page_attribute "page_title" %}{% endblock title %}
{% block content %}
<div class="jumbotron">
{% placeholder "feature" %}
</div>
<div>
{% placeholder "content" %}
</div>
{% endblock content %}
menu.html
{% load i18n menu_tags cache %}
{% for child in children %}
<li class="{% if child.ancestor %}ancestor{% endif %}
{% if child.selected %} active{% endif %}
{% if child.children %} dropdown{% endif %}">
{% if child.children %}
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
{{ child.get_menu_title }} <span class="caret"></span>
</a>
<ul class="dropdown-menu">
{% show_menu from_level to_level extra_inactive extra_active template "" "" child %}
</ul>
{% else %}
<span>{{ child.get_menu_title }}</span>
{% endif %}
</li>
{% if class and forloop.last and not forloop.parentloop %}{% endif %}
{% endfor %}
page.html
{% extends "base.html" %}
{% load cms_tags %}
{% block title %}{% page_attribute "page_title" %}{% endblock title %}
{% block content %}
{% placeholder "content" %}
{% endblock content %}
I have read their documentation but I haven't found anything related to some custom template integration. Could anyone please lead me in the right direction ?
EDIT1:
I have added in CMS_TEMPLATES:
CMS_TEMPLATES = (
## Customize this
('page.html', 'Page'),
('feature.html', 'Page with Feature'),
('index.html', 'oriel.io') # this is what I added
)
but nothing happened.
Add your templates to CMS_TEMPLATES in your settings file.
I recently met the same problem! So let me try to explain
1) You should extend PageAdmin in admin.py
In admin side, when you want to choose template for page ('advanced settings') it will call AdvancedSettingsForm by default. but we must to extend too to give your templates.
class ExtendedPageAdmin(PageAdmin):
def get_form_class(self, request, obj=None, **kwargs):
if 'advanced' in request.path_info:
return ExtendedAdvancedSettingsForm
elif 'permission' in request.path_info:
return PagePermissionForm
elif 'dates' in request.path_info:
return PublicationDatesForm
return self.form
and DO NOT forget unregister and register
admin.site.unregister(Page)
admin.site.register(Page, ExtendedPageAdmin)
2) OK) You have choosen ('advanced settings') and there must be choice among your custom templates.
class ExtendedAdvancedSettingsForm(AdvancedSettingsForm):
def __init__(self, *args, **kwargs):
super(ExtendedAdvancedSettingsForm, self).__init__(*args, **kwargs)
template_choices = [(x, _(y)) for x, y in get_cms_setting('TEMPLATES')]
self.fields['template'] = forms.ChoiceField(choices=template_choices)
3) Ok, wee see custom templates for page, but there will be error if you want to save it. It's because of Page model. It looks like this:
#python_2_unicode_compatible
class Page(six.with_metaclass(PageMetaClass, MP_Node)):
"""
A simple hierarchical page model
"""
...
template_choices = [(x, _(y)) for x, y in get_cms_setting('TEMPLATES')]
...
template = models.CharField(_("template"), max_length=100,
choices=template_choices, default=TEMPLATE_DEFAULT
help_text=_('The template used to render the content.'))
4) So you should change template_choice during init the Page object. Let's use signals
def after_page_init(sender, instance, **kwargs):
instance._meta.get_field_by_name('template')[0]._choices = []
def patch_cms_page():
from cms.models import Page
from django.db.models.signals import post_init
post_init.connect(after_page_init, sender=Page)
and finally call patch_cms_page() in urls.py )

Slim, Twig - how to pass var to Twig to base template

I would like to show the number of unreaded msgs in User Panel Box which will appear everytime when user is logged in.
How to pass the number of msg from controler to the user panel box which is included in base layout?
I can't use routes for that because the panel appears on all pages (index as well).
Now i'm sending it using global session but i think it could be done better. Any clues ?
Controler:
if(isset($_SESSION['user_id'])){
$unreaded=Model::factory('Message')->filter('getUnreadedGroups',$_SESSION['user_id']);
$_SESSION['unreaded']=$unreaded->opened;}
Base layout
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="/css/reset.css" />
<link rel="stylesheet" href="/css/style.css" />
<title>{% block page_title %} {% endblock %}</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="/js/jquery.scripts.js"></script>
</head>
<body>
<div id="all">
<div id="top-container">
<div id="logo">test</div>
<div id="search-box"></div>
</div>
<div id="left-side">
<div class="menu">
<ul>
<li class="nav_dashboard active">Strona główna</li>
<li class="nav_graphs">Wzory</li>
<li class="nav_forms">Najnowsze</li>
<li class="nav_typography">Najlepiej oceniane</li>
</ul>
</div>
</div>
<div id="page">
{% block content %} {% endblock %}
</div>
<div id="right-side">
<div id="login-container">
{% if session.user_id is defined %}
{% include 'user_panel.php' %}
{% else %}
{% include 'login_form.php' %}
{% endif %}
</div>
</div>
</div>
</body>
</html>
User Panel Box
<div class="login-top" id="login-form-top">
<div id="welcome">Witaj, <span>John Doe</span></div>
<p id="last-login">Ostatnie logowanie:</p>
<div id="logout-msg-container">
<div class="logut">Wyloguj</div>
<a id="msg-number" href="/profil/wiadomosci">
<span class="number">
{% if session.unreaded >0 %}
{{ session.unreaded }}
{% else %} 0
{% endif %}
</span>
</a>
</div>
</div>
<div class="menu">
<p class="header">Profil użytkownika</p>
<ul>
<li>Twoje Dane</li>
<li>Twoje zbiory</li>
<li>Twoje wiadomości</li>
</ul>
</div>
Typical template
{% extends 'layout.php' %}
{% block page_title %}Najnowsze pliki{% endblock %}
{% block content %}
<div id="page-top">
<h1>Najnowsze</h1>
<p>+ <span class="blue">12</span> wzorów</p>
</div>
<div id="main-topvote">
<div class="title">Najnowsze<span>( ostatni tydzień )</span></div>
<div class="content">
{% for file in files %}
<p>{{ file.idFile }}<br/> {{ file.date_add }}<br/> {{ file.desc }}<br/> {{ file.title }}<br/><br/></p>
{% else %}
<p>There are currently no articles.</p>
{% endfor %}
</div>
</div>
{% endblock %}
I havent tested this ( https://github.com/fabpot/Twig/issues/293 ):
Base layout:
...
<div id="right-side">
{% block side %}
{% block side-login %}
{% if session.user_id is defined %}
{% include 'user_panel.php' %}
{% else %}
{% include 'login_form.php' %}
{% endif %}
{% endblock %}
{% endblock %}
</div>
...
Typical template:
...
{% block side %}
{% set count = 12 %}
{% block side-login %}
{{ parent() }}
{% endblock %}
{% endblock %}
...
So you can use {{count}} in your User Panel Box.
You can also try to skip the side-login block definition .. but i am not sure.