I've created my own theme for Pelican and I've been using it for a while to build my site. I've decided to start blogging again so I'm only now adding the blog features to the site.
I've created my own blog.html template to render the content in the way I want. I started by copying and pasting the code from the 'simple' theme that comes with Pelican to get me started, but even though it is unchanged I'm getting an 'articles_page' is undefined error when I try to build.
Where is the article_page variable set from? I tried adding to my pelicanconf.py file but it didn't help.
{% extends 'base.html' %}
{% block title %}{{ page.title }} — Ricky White{% endblock title %}
{% block content %}
<section class="wrapper">
<div class="container">
<div class="row">
<div class="col">
<ol id="post-list">
{% for article in articles_page.object_list %}
<li><article class="hentry">
<header> <h2 class="entry-title">{{ article.title }}</h2> </header>
<footer class="post-info">
<time class="published" datetime="{{ article.date.isoformat() }}"> {{ article.locale_date }} </time>
<address class="vcard author">By
{% for author in article.authors %}
<a class="url fn" href="{{ SITEURL }}/{{ author.url }}">{{ author }}</a>
{% endfor %}
</address>
</footer><!-- /.post-info -->
<div class="entry-content"> {{ article.summary }} </div><!-- /.entry-content -->
</article></li>
{% endfor %}
</ol><!-- /#posts-list -->
{% if articles_page.has_other_pages() %}
{% include 'pagination.html' %}
{% endif %}
</div>
</div>
</div>
</section>
{% endblock content %}
You must have referenced your template from one of the articles using:
Template: blog
If you remove that reference and add the following lines to your pelicanconf.py, Pelican will generate blog.html directly from your template file:
DIRECT_TEMPLATES = ['index', 'blog']
PAGINATED_DIRECT_TEMPLATES = ['blog']
(Do not forget to empty your output folder before running pelican. Tested on Pelican 3.7.1)
For the sake of future visitors who might come here looking for an answer like I did:
The problem can have a good number of very diverse reasons. In my case it was not a problem with the configuration of the pelican tooling, but rather an error in the metadata of some of my content pages. I had not included the correct category, date or tag fields. You'd never guess that from the error message now, would you?
I found this question looking for the same error.
In my case the reason was an issue which has been closed but not merged in the current release of the Attila theme. More precisely: the error is caused by a template in the templates folder of the theme which has a wrong reference inside it. In the specific case, inside the page template there was a wrong reference to article.
Changing the template manually fixed the issue:
--- a/attila-1.3/templates/page.html
+++ b/attila-1.3/templates/page.html
## -21,8 +21,8 ##
{% else %}
{% set selected_cover = SITEURL+"/"+HEADER_COVER %}
{% endif %}
-{% elif article.color %}
- {% set selected_color = article.color %}
+{% elif page.color %}
+ {% set selected_color = page.color %}
{% elif HEADER_COLOR %}
{% set selected_color = HEADER_COLOR %}
{% endif %}
I hope this helps debugging similar errors.
The page variable articles_page is set in only one place: Writer._get_localcontext and there is a guard condition:
if paginated and template_name in self.settings['PAGINATED_TEMPLATES']:
# ... code ...
paginated_kwargs.update(
{'%s_paginator' % key: paginator,
'%s_page' % key: page, # <-- Creates `article_page`
'%s_previous_page' % key: previous_page,
'%s_next_page' % key: next_page})
If this problem crops up, the easiest solution is to make sure the guard condition evaluates to True. Most likely, the problem is that template_name is not in PAGINATED_TEMPLATES in your configuration file. I opened writers.py, added a print(f"template_name is {template_name}") and got my answer (I didn't have author : None in my PAGINATED_TEMPLATES dictionary).
Related
I've got some basic experience building websites using a LAMP stack. I've also got some experience with data processing using Python. I'm trying to get a grip on the mongodb-flask-python thing, so I fired everything up using this boilerplate: https://github.com/hansonkd/FlaskBootstrapSecurity
All is well.
To experiment, I tried declaring a variable and printing it...
I get this error message:
TemplateSyntaxError: Encountered unknown tag 'x'. Jinja was looking for the following tags: 'endblock'. The innermost block that needs to be closed is 'block'.
Here's my main index.html page
{% extends "base.html" %}
{% block content %}
<div class="row">
<div class="col-xs-12">
Hello World, at {{ now }}, {{ now|time_ago }}
</div>
</div>
<div class="row-center">
<div class="col">
{% x = [0,1,2,3,4,5] %}
{% for number in x}
<li> {% print(number) %}
{% endfor %}
</div>
</div>
{% endblock %}
I love learning new things, but man, can I ever get hung up for hours on the simplest of things... any help would be greatly appreciated!!!
Flask uses Jinja as its default templating engine.
The templating language is python-esque, but is not python. This is different from something like a phtml file, which is php interspersed with html.
Check the jinja documentation for more of what you can do, but here's how you set a variable within a template:
{% set x = [0,1,2,3,4,5] %}
http://jinja.pocoo.org/docs/2.9/templates/#assignments
Try this:
{% set x = [0,1,2,3,4,5] %}
See Jinja docs.
I have a static homepage, but I'm also using the i18n subsites plugin. So for the homepage I have, in pelicanconf.py:
INDEX_SAVE_AS = 'blog/index.html'
INDEX_URL = 'blog'
and for the English version:
I18N_SUBSITES = {
'en': {
'OUTPUT_PATH': 'output/en/',
'INDEX_SAVE_AS': 'blog/index.html',
'INDEX_URL': 'blog',
}
}
(truncated unnecessary bits)
The problem lies with the translation link for the homepage. The translations macro has:
{% for translation in article.translations %}
{{ translation.lang | lookup_lang_name }}
So for the English-language homepage I could either set the url and output filename as:
<meta name="save_as" content="en/index.html">
<meta name="url" content="en/">
Which makes the translation link go to site.com/en/en/ (and works), or set them as:
<meta name="save_as" content="index.html">
<meta name="url" content="/">
Which conflicts with the standard-language homepage.
Another, related problem is that the index page (blog page) has no translation link to the English or back to the standard-language version whatsoever.
What can I do to solve this?
I was able to solve my problem with the following translations macro:
{% macro translations_for(article) %}
{% if extra_siteurls %}
{% for lang, url in extra_siteurls.items() %}
{% if article %}
{{ lang | lookup_lang_name }}
{% else %}
{{ lang | lookup_lang_name }}
{% endif %}
{% endfor %}
{% endif %}
{% endmacro %}
And by adding a permalink option the each article and page I can also translate the URL for said article or page (otherwise you could just use slug in the above macro).
Last but not least I also removed the url and save_as data from both homepages.
To fix the blog page, I added this to the index.html template:
{% block translation_links %}
{% if lang == 'nl' %}
English
{% else %}
Nederlands
{% endif %}
{% endblock %}
For the second part of your question, have a look at creating language buttons
I am making some generic templates for my projects like the message template given below.
{% extends base_name %}
{% block main-contents %}
<h2>{{ message_heading }}</h2>
<div class="alert alert-{{ box_color|default:"info" }}">
{{ message }}
{% if btn_1_text and btn_1_url %}
{{ btn_1_text }}
{% endif %}
{% if btn_2_text and btn_2_url %}
{{ btn_2_text }}
{% endif %}
</div>
{% endblock %}
I can set the name of the base template through template variables. My question is whether there is a method to set the name of the block using template variables. Usually I use the block name main-contents for almost all of my project. But that is not granted for all the projects. If this is not possible using template is there a way to rename the block using python code ?
I found a hack. I dont know if this has any after effects. Can any one verify this ?
def change_block_names(template, change_dict):
"""
This function will rename the blocks in the template from the
dictionary. The keys in th change dict will be replaced with
the corresponding values. This will rename the blocks in the
extended templates only.
"""
extend_nodes = template.nodelist.get_nodes_by_type(ExtendsNode)
if len(extend_nodes) == 0:
return
extend_node = extend_nodes[0]
blocks = extend_node.blocks
for name, new_name in change_dict.items():
if blocks.has_key(name):
block_node = blocks[name]
block_node.name = new_name
blocks[new_name] = block_node
del blocks[name]
tmpl_name = 'django-helpers/twitter-bootstrap/message.html'
tmpl1 = loader.get_template(tmpl_name)
change_block_names(tmpl1, {'main-contents': 'new-main-contents})
This seems to work for now. I want to know if this method has any after effects or other issues.
i'm very new to Jinja and Flask
I want to set different background color in the navigation bar to indicate the current page.
Is there any built-in Jinja variable or method that returns current HTML pages? If possible, I want the code that doesn't need to communicate with the Python file.
So if i'm currently in index.html, it will return "index" or "index.html"
Here's my navigation code in my template:
<ul>
{% for item in navigation %}
<a href="{{url_for(item.route)}}">
<li>
{{item.text}}
</li>
</a>
{% endfor %}
</ul>
I want to add if statement so the current page will get <li> that has class
{% if ??? %}
<li class="current">
...
</li>
{% else %}
...
{% endif %}
Thank You
There is a trick in jinja2 document for your problem: http://jinja.pocoo.org/docs/tricks/
If your list is simple enough, just using request object, something like that:
<li {% if request.endpoint == item.endpoint %} class='active' {% endif %}>
{{item.text}}
</li>
Normally, I write this snippet to a macro with an explicit argument to set active:
{% macro render_sitem(endpoint, display, cls='', icon-cls='', active='') %}
<li {% if request.endpoint == endpoint or active == endpoint %} class='active' {% endif %}>
<a class='{{cls}}' href="{{url_for(endpoint)}}"><i class="{{icon-cls}}"></i> {{display}}</a>
</li>
{% endmacro %}
The list will be something like:
<ul class="nav nav-list">
{{render_sitem('page.index', _('Pages'), icon-cls='icon-sitemap', active=active_page)}}
{{render_sitem('post.index', _('Posts'), icon-cls='icon-file', active=active_page)}}
{{render_sitem('user.index', _('Users'), icon-cls='icon-group', active=active_page)}}
</ul>
So if you have a child page which extends or includes your list, you can set active item like:
{% set active_page = 'page.index' %}
in the top of your child page.
In pyramid 1.5 there are no method like request.endpoint in Flask.
We use custom filter get_endpoint
request.path|get_endpoint
jinja2_custom_filters.py:
from pyramid_jinja2 import Environment
def get_endpoint(str):
"""
:param str:
:return:
"""
return str.split('/')[-1]
env = Environment()
env.filters['get_endpoint'] = get_endpoint
and in development.ini:
jinja2.filters =
model_url = pyramid_jinja2.filters:model_url_filter
route_url = pyramid_jinja2.filters:route_url_filter
static_url = pyramid_jinja2.filters:static_url_filter
get_endpoint = path to ... jinja2_custom_filters.get_endpoint
Maybe it will be useful to someone :)
In Flask 2.0.1, the request object is available in the template. With this you can easily use it to check the page using the request.path attribute.
An example of a check would be like this:
{% if request.path == "/" %}
<h1>You are at the root</h1>
{% endif %}
I'm relatively new to Django and I'm trying to build up my toolbox for future projects. In my last project, when a built-in template tag didn't do quite what I needed, I would make a mangled mess of the template to shoe-horn in the feature. I later would find a template tag that would have saved me time and ugly code.
So what are some useful template tags that doesn't come built into Django?
I'll start.
http://www.djangosnippets.org/snippets/1350/
Smart {% if %} template tag
If you've ever found yourself needing more than a test for True, this tag is for you. It supports equality, greater than, and less than operators.
Simple Example
{% block list-products %}
{% if products|length > 12 %}
<!-- Code for pagination -->
{% endif %}
<!-- Code for displaying 12 products on the page -->
{% endblock %}
smart-if. Allows normal if x > y constructs in templates, among other things.
A better if tag is now part of Django 1.2 (see the release notes), which is scheduled for release on March 9th 2010.
James Bennet's over-the-top-dynamic get_latest tag
edit as response to jpartogi's comment
class GetItemsNode(Node):
def __init__(self, model, num, by, varname):
self.num, self.varname = num, varname
self.model = get_model(*model.split('.'))
self.by = by
def render(self, context):
if hasattr(self.model, 'publicmgr') and not context['user'].is_authenticated():
context[self.varname] = self.model.publicmgr.all().order_by(self.by)[:self.num]
else:
context[self.varname] = self.model._default_manager.all().order_by(self.by)[:self.num]
return ''
<div id="news_portlet" class="portlet">
{% get_sorted_items cms.news 5 by -created_on as items %}
{% include 'snippets/dl.html' %}
</div>
<div id="event_portlet" class="portlet">
{% get_sorted_items cms.event 5 by date as items %}
{% include 'snippets/dl.html' %}
</div>
I call it get_sorted_items, but it is based on James' blog-post
In come case {% autopaginate queryset %} (http://code.google.com/p/django-pagination/) is useful. For example:
#views.py
obj_list = News.objects.filter(status=News.PUBLISHED)
# do not use len(obj_list) - it's evaluate QuerySet
obj_count = obj_list.count()
#news_index.html
{% load pagination_tags %}
...
# do not use {% if obj_list %}
{% if obj_count %}
<div class="news">
<ul>
{% autopaginate obj_list 10 %}
{% for item in obj_list %}
<li>{{ item.title }}</li>
{% endfor %}
</ul>
</div>
{% paginate %}
{% else %}
Empty list
{% endif %}
Note, that obj_list must be lazy - read http://docs.djangoproject.com/en/dev/ref/models/querysets/#id1