how to import a block of a template in jinja2 - python

I want to use jinja2 to design a template that will be rendered as an article whose chapters and sections should be combined freely. So I create a base.html as a skeleton. The problem is that the chapters and sections contain some reusable table and image elements, and if I use these elements as 'macro', then it will be difficult to use chapters and sections as 'macro' too. But if I use chapters and sections as 'block', how can I import 'block' into the skeleton? And some local variables must be passed into chapters and sections.
Here is an example of my script. The script reads config.json and turns it into a dict to pass to the base.html for rendering. The actual number of chapters and sections are much more than that I represent in the example, with multiple paragraphs, and the number of type of components too.
#config.json
{"templates":[
{"title":"chapter1",
"children":[
{"title":"chapter1_1","template":"template1.html","block":"block1"},
{"title":"chapter1_2","template":"template2.html","block":"block1","parameter":{"note":"hello world"}},
]},
{"title":"chapter2","template":"template1.html","block":"block2","parameter":{"note":"blabla"}}
]}
#base.html
{% from "component.html" import common_table as common_table with context %}
{% from "component.html" import common_img as common_img with context %}
{%- for chapter in chapter_list %}
{%- set ch_loop = loop %}
<h2>{{ ch_loop.index }} {{ chapter.title }}</h2>
{%- if chapter.children %}
{%- for section in chapter.children %}
<h3>{{ ch_loop.index }}.{{ loop.index }} {{ section.title }}</h3>
{% import section.template as template with context %}
{% set parameter=section.parameter %}
{{ template.blocks[section.block] }}
{%- endfor %}
{%- else %}
{% import chapter.template as template with context %}
{% set parameter=chapter.parameter %}
{{ template.blocks[chapter.block] }}
{%- endif %}
{%- endfor %}
#template1.html
{% block block1 %}
I am block 1
{{ common_table(id="table1",head="nohead") }}
{{ common_img(src="css/icon/icon1.png") }}
{% endblock %}
{% block block2 %}
I am block 2
{{ common_img(src="css/icon/icon2.png") }}
{% if parameter.note=="blabla" %}
{{ "blabla~blabla~" }}
{% endif %}
{% endblock %}
#component.html
{% macro common_table(id, name,note, head="onehead") %}
{% if name %}
<b class="tablename">{{ name }}</b>
{% endif %}
<table id="{{ id }}" class=" {{ head }}"></table>
{% if note %}
<p class="tablenote">{{ note }}</p>
{% endif %}
{% endmacro %}
{% macro common_img(src, alt, name) %}
<img src="{{ src }}" alt="{{ alt }}">
{% if name %}
<b class="imgname">{{ name }}</b>
{% endif %}
{% endmacro %}
I searched and found that the template object in script seems to have 'blocks' attribute, so I tried to import template files as an object and use '.blocks' to get the block attribute of template object, but it gave me an error as following:
jinja2.exceptions.UndefinedError: 'jinja2.environment.TemplateModule object' has no attribute 'blocks'
I checked the code of jinja2 and found that the imported template object is 'TemplateModule' class, different from the 'Template' class in script, and the 'TemplateModule' class doesn't seem to have 'blocks' attribute, even doesn't export blocks .
So how can I import a block of a template ? Or should I change my jinja2 statements?

Related

How to render the DateField on a page in django

Hello I just started learning django and I am having problems rending the content the way I want to. Ideally I want to manage a system of tickets and have the ticket number, start-date, end-date and status appear on the page. Similar to the below format
{% extends 'base.html' %}
{% block content %}
<h1>test</h1>
{% for cr in crs %}
<p>{{ cr }}</p>
{% endfor %}
{% endblock content %}
From what I have in my views file the only thing being displayed when i view it in my web browser is only the ticket number.
Any help would be appreciated.
You should render the attributes .start_date and .end_date in your template as well, so:
{% for cr in crs %}
{{ cr.cr_number }} {{ cf.start_date }} {{ cr.end_date }} {{ cr.get_status_display }}
{% endfor %}
You can specify the date format with the |date template filter [Django-doc]:
{% for cr in crs %}
{{ cr.cr_number }} {{ cf.start_date|date:"Y-m-d" }} {{ cr.end_date|date:"Y-m-d" }} {{ cr.get_status_display }}
{% endfor %}

Extending Django admin delete confirmation page

I am wondering if it is possible to extend Django Admin's delete confirmation page for specific app and model. I want the functionality that enable user to delete all records like that of django admin interface. it is possible to extends delete confirmation.html in my app
You can extend the Django admin delete confirmation page. To extend it, in your templates directory, create a directory named admin and create an html file named delete_selected_confirmation.html with the below content (the default admin delete confirmation page source)
{% extends "admin/base_site.html" %}
{% load i18n l10n admin_urls static %}
{% block extrahead %}
{{ block.super }}
{{ media }}
<script src="{% static 'admin/js/cancel.js' %}" async></script>
{% endblock %}
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} delete-confirmation delete-selected-confirmation{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
{% translate 'Home' %}
› {{ opts.app_config.verbose_name }}
› {{ opts.verbose_name_plural|capfirst }}
› {% translate 'Delete multiple objects' %}
</div>
{% endblock %}
{% block content %}
{% if perms_lacking %}
<p>{% blocktranslate %}Deleting the selected {{ objects_name }} would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:{% endblocktranslate %}</p>
<ul>
{% for obj in perms_lacking %}
<li>{{ obj }}</li>
{% endfor %}
</ul>
{% elif protected %}
<p>{% blocktranslate %}Deleting the selected {{ objects_name }} would require deleting the following protected related objects:{% endblocktranslate %}</p>
<ul>
{% for obj in protected %}
<li>{{ obj }}</li>
{% endfor %}
</ul>
{% else %}
<p>{% blocktranslate %}Are you sure you want to delete the selected {{ objects_name }}? All of the following objects and their related items will be deleted:{% endblocktranslate %}</p>
{% include "admin/includes/object_delete_summary.html" %}
<h2>{% translate "Objects" %}</h2>
{% for deletable_object in deletable_objects %}
<ul>{{ deletable_object|unordered_list }}</ul>
{% endfor %}
<form method="post">{% csrf_token %}
<div>
{% for obj in queryset %}
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}">
{% endfor %}
<input type="hidden" name="action" value="delete_selected">
<input type="hidden" name="post" value="yes">
<input type="submit" value="{% translate 'Yes, I’m sure' %}">
{% translate "No, take me back" %}
</div>
</form>
{% endif %}
{% endblock %}
now the directory and file structure should look like this. Now you can extend the above template as per your need.
├── templates
   └── admin
      └── delete_selected_confirmation.html

How to pass template variable to slice filter in Django templates

I'm trying to slice loop in django template with variable
USUAL WAY
{% for article in module.module_article_key.module_article_category.article_category_key.all|slice:":2" %}
{{ article.article_title }}
{% endfor %}
WHAT NEEDS
{% for article in module.module_article_key.module_article_category.article_category_key.all|slice:":module.module_article_key.module_article_count" %}
{{ article.article_title }}
{% endfor %}
so we have working variable {{ module.module_article_key.module_article_count }}
normaly this variable gives integer value stored for this module, however wen i use it to slice loop - nothing happens
You need to cast module_article_count to string first then making articleSlice via nested {% with %} and use the resulting template variable in slice filter as follow:
{% with articleCount=module.module_article_key.module_article_count|stringformat:"s" %}
{% with articleSlice=":"|add:articleCount %}
{% for article in module.module_article_key.module_article_category.article_category_key.all|slice:articleSlice %}
{{ article.article_title }}
{% endfor %}
{% endwith %}
{% endwith %}

How to determine wagtail Page content type within django template?

The core problem is that handling of wagtail RichTextField and StreamField is radically different in the templates.
I'm trying to accomplish something similar to the following:
{% with post=post.specific %}
{% if post.content_type == 'streamfield' %}
{% include_block post.body %}
{% else %}
{{ post.body|richtext }}
{% endif %}
{% endwith %}

Django assignment_tag conditional

I'm trying to show partials based on a simple condition. My condition is whether an assignment_tag is True or False.
Templatetag:
from django import template
register = template.Library()
#register.assignment_tag
def partner():
return False
Template:
{% load partner_check %}
{% if partner %}
{% block header %}
{% include 'includes/partner_header.djhtml' %}
{% endblock header %}
{% block footer %}
{% include 'includes/partner_footer.djhtml' %}
{% endblock footer %}
{% endif %}
No matter what I set partner to, the blocks still appear. What am I missing?
Firstly, that's not how assignment tags work. You have never actually called the tag; if partner refers to a (non-existent) template variable named "partner". You call an assignment tag by using it on its own along with a variable to assign it to:
{% partner as partner_value %}
{% if partner_value %}...{% endif %}
Secondly, that's not how blocks work either. You can't dynamically define blocks; they are part of the basic structure of a template, not something that is assigned during evaluation.
I accomplished this by using a context_processor (https://docs.djangoproject.com/en/1.7/ref/settings/#std:setting-TEMPLATE_CONTEXT_PROCESSORS)
Context Processor:
def partners(context):
return {
'partner': False
}
Template:
{% block header %}
{% if partner %}
{% include 'includes/partner_header.djhtml' %}
{% else %}
{{ block.super }}
{% endif %}
{% endblock header %}
{% block footer %}
{% if partner %}
{% include 'includes/partner_footer.djhtml' %}
{% else %}
{{ block.super }}
{% endif %}
{% endblock footer %}

Categories