Here's a simple template structure that consists of three files:
wrapper.html, which defines the basic structure of a page. It has some blocks that can be extended.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<script type="text/javascript" src="/something.js"></script>
<link rel="stylesheet" type="text/css" href="/style.css">
<title>{{ title }}</title>
</head>
<body>
{% block header %}
{% endblock %}
{% block body %}
{% endblock %}
</body>
</html>
main.html is the the file that I give to jinja2 to format.
{% extends "wrapper.html" %}
{% set title = title | default("Untitled") %}
{% block header %}
<h1>Welcome to {{ title }}</h1>
{% endblock %}
{% block body %}
{% include "included.html" %}
{% endblock %}
and included.html has some extra stuff I don't want to put into main.html for whatever reason
<p>In this page ({{ title }}), we will discuss all kinds of things.</p>
<p>Blah blah blah...</p>
My problem is that when missing a title, everything gets filled with "Untitled" except for one place: the included.html file.
I have found two ways of fixing this.
Add {% set title = title %} inside the {% block body %} of main.html (What? Why does that even work?)
Move the {% set title = title | default("Untitled") %} to wrapper.html
I like neither of these options. The first one for obvious reasons, and the second one because if I might want to extend wrapper.html in a number of ways and "Untitled" may not always be the best choice for an untitled page.
So my question is this: Is there any way I can I get included.html to recognize variables from main.html that are not directly defined in the block scope?
I would also like to know if I'm using Jinja2 incorrectly.
Related
I have read the other answers on this topic and still do not see what I am missing. Not sure if it is something with vs code and the extensions I have added as I type out code as per the training video and when I save the code it get compressed?
My base.html file code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{% block page_title %}{% endblock page_title %}</title>
</head>
<body>
{% block content %}{% endblock content%}
</body>
</html>
The code in the index file where I want to use the base.html format, looks like this after I have saved it. As you can see vs code compress it - is that the issue and if so how do I fix?
{% extends "base.html" %} {% block page_title %} All challenges {% endblock
page_title %} {% block content %}
<ul>
<li>{{ month|title}}</li>
</ul>
{% endblock content %}
The extensions I have is Django Template, Prettier, Django I am thinking it is something with my preferences that cause this.
I have re-typed and double check the spacing around the {% to make sure as I see that is the most common solution.
I have also tried the just using {% endblock %} without the block names but still get the same error.
Here in your code Prettier extension auto format page so title block is start with first line and end with second line.
html templete can't understand DTL(jinja) reading so django tempale engine fatch an error
so just rearrange it like this...
{% extends "base.html" %}
{% block page_title %} All challenges {% endblockpage_title %}
{% block content %}
<ul>
<li>{{ month|title}}</li>
</ul>
{% endblock content %}
Shopify creates a URL to each collection filter. This URL https://example.com/collections/default/type_tag+size_tag+width_tag would filter products on a collection called default to show products that are tagged with type_tag, size_tag, width_tag.
This also creates a canonical link with the same href as the above URL. In this example, the canonical href would be <link rel="canonical" href="https://example.com/collections/default/type_tag+size_tag+width_tag">
We want to optimize for SEO. For URLs with the same filters but inverse (and therefore yield the same page and filtered content) we would like to have the same canonical href.
For example: These URLs would filter the same products on collections default and show canonicals with matching href value.
https://example.com/collections/default/type_tag+size_tag+width_tag
https://example.com/collections/default/size_tag+width_tag+type_tag
https://example.com/collections/default/type_tag+width_tag+size_tag
https://example.com/collections/default/width_tag+type_tag+size_tag
Regardless of the URLs above, we would like the canonical href to be fixed as the one we set. So as an example, we want the above URLs to have https://example.com/collections/default/type_tag+size_tag+width_tag as the canonical.
As you can tell, our tags are grouped into type_, size_ and width_.
I have tried several methods to loop over the {% current_tags %} object to check if any of the tags in {% current_tags %} contains type_, size_ and width_. Below is the idea that I have but clearly it doesn't work so it's trash. Fresh ideas please and thank you!!!
{% if template contains 'collection' and current_tags %}
{% for tag in current_tags %}
{% if current_tags contains 'type_' %}
{% assign type_tag_url = tag %}
{% elsif current_tags contains 'size_' %}
{% assign size_tag_url = tag %}
{% elsif current_tags contains 'width_' %}
{% assign width_tag_url = tag %}
{% endif %}
{% endfor %}
<link rel="canonical" href="{{ shop.url }}{{ collection.url }}/{{type_tag_url}}+{{size_tag_url}}+{{width_tag_url}}" />
{% else %}
<link rel="canonical" href="{{ canonical_url }}">
{% endif %}
The current_tags is an array. When you use contains operator to find items in the array the comparison works based on an exact match. So you cannot use it to check whether it contains tags that contain a part of the string, like type_. Check the tags itself instead e.g.:
{% if template contains 'collection' and current_tags %}
{% for tag in current_tags %}
{% if tag contains 'type_' %}
{% assign type_tag_url = tag %}
{% elsif tag contains 'size_' %}
{% assign size_tag_url = tag %}
{% elsif tag contains 'width_' %}
{% assign width_tag_url = tag %}
{% endif %}
{% endfor %}
<link rel="canonical" href="{{ shop.url }}{{ collection.url }}/{{type_tag_url}}+{{size_tag_url}}+{{width_tag_url}}" />
{% else %}
<link rel="canonical" href="{{ canonical_url }}">
{% endif %}
I have a simple Blog site where the front page index is a list of posts, non truncated and rendered exactly like the individual pages.
I have the index page setup and working:
---
layout: default
---
<div>
{% for post in site.posts %}
{% include post/post.html %}
{% endfor %}
</div>
Where post/post.html contains the post layout using the post variable like so:
<article>
<header>
{% include post/title.html %}
{% include post/metadata.html %}
</header>
<div class="entry-content" itemprop="text">
{{ post.content }}
</div>
</article>
Now, on a specific post page, I want to reuse this include layout so that I can keep my code DRY, so I have the posts use the post.html layout (different from posts/post.html above):
---
layout: default
comments: true
---
{% include post/post.html %}
but the problem is that the include file expects a post variable to exist such post.content is how you access the content.
I have tried:
{% assign post = page %}
and that seems to be the right to pass a variable in, but page is not the right one as it renders as a markdown string instead of the html on the page.
So, how can I pass self -- or whatever is needed -- so that the include file does not need to be altered for the index page or the post page, thus sharing the same code?
While #David Jacquel's answer work, I found it to be unclean and a little verbose, though it did get me on the right track.
_includes/post/post.html swaps the {{ post.content }} for {{ body }}
<article>
<header>
{% include post/title.html %}
{% include post/metadata.html %}
</header>
<div class="entry-content" itemprop="text">
{{ body }}
</div>
</article>
_layouts/index.html now uses
{% assign body = post.content %}
{% include post/post.html %}
_layouts/post.html uses:
{% assign post = page %}
{% assign body = content %}
{% include post/post.html %}
Simple.
We can do it ! With some layout and variable passing.
Regular post use post layout :
---
layout: post
....
---
post content ...
A custom post use the custom_post layout (_layouts/custom_post.hmtl)
---
layout: custom_post
...
---
post content ...
The _layouts/custom_post.hmtl layout just calls our post include, passing the page variable :
---
layout: default
---
{% include post/post.html page=page %}
And finally the _includes/post/post.html conditionally assign the post variable if the page variable is set :
{% if include.page %}
{% comment %}
This only append in the custom_post view context
{% endcomment %}
{% assign post = include.page %}
{% endif %}
<article>
<header>
{% include post/title.html %}
{% include post/metadata.html %}
</header>
<div class="entry-content" itemprop="text">
{{ post.content }}
</div>
</article>
Django template system lets you easily specify a template and fill it with different data using extends and blocks.
What I need to do is to have several templates, filled with the same data (blocks) while avoiding code repetition. It sounds like a usecase for templatetags but consider this example:
<div class="container">
{% get_tags page as tags %}
{% if tags %}
<div class="ribbon">
<span class="ribbon-inner">{{ tags|join:' | ' }}</span>
</div>
{% endif %}
</div>
If I wanted to display the tags in another template using a different html elements/classes I would have to create at least two templatetags (has_tags and get_tags) or include html in templatetags code.
I'd like to have something like this:
#common.html
{% block tags %}
{% get_tags page as tags %}
{% if tags %}
<div class="ribbon">
<span class="ribbon-inner">{{ tags|join:' | ' }}</span>
</div>
{% endif %}
{% endblock %}
#template_A.html
{% include common.html %}
<div class="container-1">
{% block tags %}
{{ block.super }}
{% endblock %}
</div>
#template_B.html
{% include common.html %}
{% block tags %}
{% get_tags page as tags %}
{{ tags|join:', ' }}
{% endblock %}
The problem is that include renders the template first, therefore it doesn't work this way. There are a lot of similar points in the file I'm editing, so creating and including template for each of them is not a great solution either.
Any thoughts?
Well, this is my solution:
#templateA.html
{% include "_common.html" with parent_file="_templateA.html" %}
#templateB.html
{% include "_common.html" with parent_file="_templateB.html" %}
#_templateA.html
<i>{% block tags %}{% endblock %}</i>
#_templateB.html
<b>{% block tags %}{{ tags|join:' & ' }}{% endblock %}</b>
#_common.html
{% extends parent_file %}
{% block tags %}
{% if not block.super %} # this does the trick
{{ tags|join:' I ' }}
{% else %}
{{ block.super }}
{% endif %}
{% endblock %}
This allows having HTML templates in _templateA.html and _templateB.html. If the block is left empty, it is filled with default from _common.html, while it can be overriden in _template.
It would be nice to override the block tag to avoid code repetition in _common.html but the following implementation fails on block.super() because of missing context.
#register.tag('overridable_block')
def overridable_block(parser, token):
from django.template.loader_tags import do_block
block = do_block(parser, token)
if block.super():
return block.parent
return block
Haven't found a way past this yet.
In Symfony 1.4 I use to include just the needed assets with:
apps/myApp/config/view.yml (general assets to be used in every page)
stylesheets: [main.css]
javascripts: [lib/jquery.js, lib/jquery.qtip.js, backend/main.js]
apps/myApp/modules/someModule/templates/someTemplateSuccess.php (assets just for this view, partial, etc)
<?php use_stylesheet('backend/datagrid.css') ?>
<?php use_javascript('backend/datagrid.js') ?>
and then finally linking those in apps/myApp/templates/layout.php:
<?php include_stylesheets() ?>
<?php include_javascripts() ?>
So, how to do this using the AsseticBundle in Twig views?
I'm really confused... thanks!
Ok, I got here:
https://github.com/kriswallsmith/symfony-sandbox/commit/f1fc1d0cf2fe69660f94f33719a4508d6e9e25ae
and it WORKS!
it goes like this:
src/MySite/MyBundle/Resources/css/datagrid.css
to include it in the view:
src/MySite/MyBundle/Resources/views/MyViews/myview.html.twig
{% block stylesheets %}
{% stylesheets '#MySiteMyBundleBundle/Resources/css/datagrid.css' %}
<link href="{{ asset_url }}" type="text/css" rel="stylesheet" />
{% endstylesheets %}
{% endblock %}
and finally, lets print it:
app/Resources/views/base.html.twig
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{% block title %}Lol!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
<link rel="shortcut icon" href="{{ asset('favicon.ico') }}" />
</head>
<body>
{% block body %}{% endblock %}
{% block javascripts %}{% endblock %}
</body>
</html>
Great!
UPDATE:
I still don't know why but:
{% stylesheets '#MySiteMyBundleBundle/Resources/css/*.css' output='css/all.css' %}
<link href="{{ asset_url }}" type="text/css" rel="stylesheet" />
{% endstylesheets %}
Only works setting debug to false, so the best way to do this is configuring it:
app/config/config.yml
# Assetic Configuration
assetic:
debug: false
use_controller: true
write_to: %kernel.root_dir%/../web
filters:
cssrewrite: ~