I'm using Python with Flask and Jinja2 and I'm trying to implement a sidebar. In the HTML pages I have got this:
{% include "sidebar.html" %}
What I want in the sidebar file is to have a block of the latest users. To do that I need to get the results from the server for the sidebar.html file. But where should I write the code for that in the python file?
The way you could implement this functionality is by creating a Jinja variable on the python side:
app = Flask(__name__)
app.jinja_env.globals.update({
'latest_users': get_latest_users()
})
def get_latest_users() {
return ['Mark', 'Jane', 'Sally']
}
The variable latest_users can now be accessed from any Jinja template simply by doing:
{% for user in latest_users %}
<p>{{ user }}</p>
{% endfor %}
You can pass variables to the templates. When you use include your variables still can be used in this included part too:
#app.route('/')
def index():
users = ['user1', 'user2']
debug = False
render_template('index.html', users=users, debug=debug)
# index.html
{% include "sidebar.html" %}
#sidebar.html
{% for user in users %}
<p>{{ user }}</p>
{% endfor %}
{{debug}}
Related
I am a rookie in Flask, and try to create dynamic input fields. I came across a solution where I can create the template in Flask and then I have to iterate in my .html file with the following code:
{% from 'your_form_template.jinja' import forms %}
{% for address_entry_form in form.addresses %}
{{ address_entry_form.hidden_tag() }}
{# Flask-WTF needs `hidden_tag()` so CSRF works for each form #}
{{ forms.render_field(address_entry_form.name) }}
{% endfor %}
I can't figure out what do I need to put in the first line instead of 'your_form_template.jinja'
I only have a simple app structure:
app
|
Templates--
| |
| Index.html
app.py
Your top line wouldn't be in your html, you'd pass the variable addresses to jinja. So in app.py import your forms module and:
#app.route('/', methods=('GET','POST'))
def index():
#stuff you're doing in index
return render_template('index.html', adresses=forms.addresses) #assuming forms.addresses here is actually a list of forms
Then the html would have
{% for address_entry_form in adresses %}
....
In my CKAN extension, I'm adding a new tab to the user dashboard. I followed the procedure described in this answer and it seemed to work. In the controller for the new page, I set the template variables in the same way as they are set for the other pages on the dashboard. When I click on the tab and load the new page, though, I get UndefinedError: 'user_dict' is undefined. What's going wrong?
Here's the relevant part of my_extension/templates/user/dashboard.html where I add the tab:
{% ckan_extends %}
{% block page_header %}
<header class="module-content page-header hug">
<div class="content_action">
{% link_for _('Edit settings'), named_route='user.edit', id=user.name, class_='btn btn-default', icon='cog' %}
</div>
<ul class="nav nav-tabs">
{{ h.build_nav_icon('dashboard.index', _('News feed')) }}
{{ h.build_nav_icon('dashboard.datasets', _('My Datasets')) }}
{{ h.build_nav_icon('dashboard.organizations', _('My Organizations')) }}
{{ h.build_nav_icon('dashboard.groups', _('My Groups')) }}
{{ h.build_nav_icon('my_extension_dashboard_owned_datasets', _('My Owned Datasets')) }}
</ul>
</header>
{% endblock %}
Here's the new template so far, my_extension/templates/user/dashboard_owned_datasets.html:
{% extends "user/dashboard_datasets.html" %}
The relevant part of the plugin class definition:
class MyThemePlugin(plugins.SingletonPlugin, DefaultTranslation):
plugins.implements(plugins.IRoutes, inherit=True)
# IRoutes
def before_map(self, map):
with SubMapper(
map, controller="ckanext.my_extension.controller:MyUserController"
) as m:
m.connect(
"my_extension_dashboard_owned_datasets",
"/dashboard/owned_datasets",
action="dashboard_owned_datasets",
)
return map
And here's the new controller, in my_extension/controller.py:
# encoding: utf-8
import logging
import ckan.lib.base as base
from ckan.common import c
from ckan.controllers.user import UserController
log = logging.getLogger(__name__)
render = base.render
class MyUserController(UserController):
def dashboard_owned_datasets(self):
context = {"for_view": True, "user": c.user, "auth_user_obj": c.userobj}
data_dict = {"user_obj": c.userobj, "include_datasets": True}
self._setup_template_variables(context, data_dict)
log.critical(c.user_dict)
return render(
"user/dashboard_owned_datasets.html"
)
As you can see, I use the UserController's _setup_template_variables method, which is used in all the other dashboard actions in that controller. That method sets c.user_dict, among other things:
def _setup_template_variables(self, context, data_dict):
c.is_sysadmin = authz.is_sysadmin(c.user)
try:
user_dict = get_action('user_show')(context, data_dict)
except NotFound:
h.flash_error(_('Not authorized to see this page'))
h.redirect_to(controller='user', action='login')
except NotAuthorized:
abort(403, _('Not authorized to see this page'))
c.user_dict = user_dict
c.is_myself = user_dict['name'] == c.user
c.about_formatted = h.render_markdown(user_dict['about'])
I'm logging c.user_dict after setting it in the controller, and I see all the data I would expect to see there.
But when I click the tab and load http://localhost:5000/dashboard/owned_datasets, I get the error UndefinedError: 'user_dict' is undefined. What am I missing?
The answer is that the IRoutes plugin interface no longer works for what I want to use it for, due to the migration of CKAN from Pylons to Flask. The IBlueprint interface should be used instead. See https://github.com/ckan/ckan/wiki/Migration-from-Pylons-to-Flask#flask-views-blueprints-and-routing for more information on blueprints and how to convert an extension from using IRoutes to IBlueprint.
When I type {{ settings }} on a template and open it with Mezzanine, it shows me {u'MEZZANINE_ADMIN_PREFIX': u'grappelli/'}. I'm trying to access settings.BLOG_SLUG, but cannot get that setting to appear in the template. Here's a small snip of what my template looks like.
{% load mezzanine_tags keyword_tags i18n %}
{% block main %}
{{ settings }}
{% endblock %}
How do I get my template to display the string stored in setting.BLOG_SLUG?
you have to pass settings.BLOG_SLUG from your view than you would be able to display it in html.
for example you have written line settings.py file like
BLOG_SLUG = 'something'
than you can retrieve it in your view as
SETTINGS.BLOG_SLUG
and you can pass it from your view to html
(Django , Python) I have created a list of book objects and it is being passed as context in my views.py along with the current session. On my template, i was to check if the books in that list are stored in the session, and if they are i want to access some info relating to that book within that session. how do i access the books in the session dynamically? is there a way?
i know i can access them by using "request.session.name" (where "name" is the same of the space in the session it is stored)
There are several book titles saved in the session, the way they are saved are as follows (in a function under views.py)
request.session["random book title"] = "random dollar price"
i want to access that "random dollar price" dynamically in a template.
this is the block of code in the template
{% for book in book_list %}
{% if book.title in request.session %}
{{ request.session.??? }}
{% endif %}
{% endfor %}
Thank you in advance!
You can make a custom template tag to look up by attribute like here
Performing a getattr() style lookup in a django template:
# app/templatetags/getattribute.py
import re
from django import template
from django.conf import settings
numeric_test = re.compile("^\d+$")
register = template.Library()
def getattribute(value, arg):
"""Gets an attribute of an object dynamically from a string name"""
if hasattr(value, str(arg)):
return getattr(value, arg)
elif hasattr(value, 'has_key') and value.has_key(arg):
return value[arg]
elif numeric_test.match(str(arg)) and len(value) > int(arg):
return value[int(arg)]
else:
return settings.TEMPLATE_STRING_IF_INVALID
register.filter('getattribute', getattribute)
Now change your template to
{% load getattribute %}
{% for book in book_list %}
{% if book.title in request.session %}
{{ request.session|getattribute:book.title }}
{% endif %}
{% endfor %}
This is a basic custom template tag example:
Django - Simple custom template tag example
and docs:
https://docs.djangoproject.com/en/1.11/howto/custom-template-tags/
From what I remember from my django days should work
You can put session data in a dictionary and send this data to target template when you want to render it in view function.
def some_function(request):
context={
'data':sessionData #put session data here
}
return render(request,"pass/to/template.html",context)
Now you can access 'data' in your template.html
I think you should just send a list of book names from your view instead of a queryset so when you are crosschecking with session you use the title directly instead.
{% for book in book_list %}
{% if book in request.session %}
{{ request.session.book }}
{% endif %}
{% endfor %}
I am using Django to build a website.
I have a context processor setup that looks something like this:
TEMPLATE_CONTEXT_PROCESSORS = (
...
"mysite.context_processors.mystandardvariables"
)
This adds some standard variables that I like to use in templates, such as SITE_NAME and SITE_ROOT.
I have just created my first custom template tag and I find that I cannot access these standard variables.
I don't get any errors and my page displays ok, it's just that the variable that I want are not available.
To check which variables are available I already used {% debug %}.
My tag looks like this:
#register.inclusion_tag('search/search_snippet.html', takes_context = True)
def search(context):
form = forms.SearchForm()
return {'form': form }
The template for the tag looks like this:
<form action="{{ SITE_ROOT }}search" method="post">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Submit">
</form>
I am including the search tag in my home page like this:
{% extends "base.html" %}
{% load search_tags %}
{% block content %}
{% search %}
{% endblock %}
To answer my own question, I figured out a way to do what I want using a normal template tag rather than an inclusion tag.
#register.tag
def search(parser, token):
return SearchNode()
class SearchNode(template.Node):
def render(self, context):
return render_to_string('search/search_snippet.html',
{ 'form' : forms.FindForm() }, context)
Here I am passing the context through to the function that renders my template to a string.
I would have preferred to implement this as an inclusion tag as it seems like less work, but I wasn't sure how to get it to work.
If anyone knows how to get this working with an inclusion tag please answer and I'll mark your question as the right answer.