Having multiple templates nested within each other using weby - python

I have set up a website using webpy.
I have my main page called layout.html. I load foo1.html into layout
$def with (content)
<html>
<head>
<title>Foo</title>
</head>
<body>
$:content
</body>
</html>
And the content inside is foo1.html
<div> Hello </div>
Is it possible to change foo1.html to also load another webpage:
$def with (secondarycontent)
<div> $:secondarycontent </div>

Just define render as template global
template_globals = {}
render_partial = template.render(template_dir, globals=template_globals)
render = template.render(template_dir, globals=template_globals,
base='layout')
template_globals.update(render=render_partial)
So now you can call it from templates
$:render.nested.template()

Related

Injecting data into html using Flask

I have a flask app, about saving strings into some db files.
I have a base.html file which is like navbar which i extend to every page. That navbar has a lots of links which require a specific string that the user has to enter, so i wanna know if there's a way to inject strings into that base.html file, cuz i can't make a route for a navbar base file right?
Navbar base file down below
<!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">
<link rel="stylesheet" href="/static/css/base.css">
<title>
BukkitList - {% block title %}{% endblock %}
</title>
</head>
<body>
<div class="NAV_B Hidden" id="MENU">
<div class="NAV_B_LINKS">
<img src="/static/assets/img/cube.png" alt="">
<a class="SUS" href="/">Home</a>
</div>
<div class="NAV_B_LINKS">
<img src="/static/assets/img/list.png" alt="">
<a class="/List{{UserId}}" href="/List">List</a>
</div>
<div class="NAV_B_LINKS">
<img src="/static/assets/img/add.png" alt="">
<a class="/Task_Add/{{UserId}}">Add Task</a>
</div>
<div class="NAV_B_LINKS">
<img src="/static/assets/img/settings.png" alt="">
<a class="SUS">Settings</a>
</div>
</div>
<div class="NAV_S" id="NAV">
<img src="/static/assets/img/cube.png" alt="">
<h3>{% block navtitle %}
{% endblock %}
</h3>
<img src="/static/assets/img/menu.png" alt="" onclick="Menu()">
</div>
{% block main %}
{% endblock %}
</body>
<script src="/static/js/base.js"></script>
</html>
Yes i need that UserId to be injected.
the question is not very understandable of where the user is inputting the {{UserID}} but from what I understand that there is that userID that you can select from the db in the Python file and you want to pass it into the HTML page or if you have a sign-in in your page, you can grab that ID when they sign in using flask_session either way if you need to pass that userID from the Python file you will need to include it in your return, so in python it will look like that if you are using session:
#app.route("/")
def main():
UserIDpy = Session["YourSessionVar"]
return render_template("YourHTMLpage.html", UserID = UserIDpy)
The UserID is the var name that will be passed into the HTML page and UserIDpy is the var name that what UserID saved at.
So that code will replace all of {{ UserID }} you have at you HTML page
I believe you can do this with Flask's session variable. It allows you to create and update a global variable that can be referenced in templates even when you don't render them directly. This is similar to Lychas' answer, but should be more suited for your purpose.
Create/update a session variable in your login route (or wherever you want to update this value) with this line:
session['UserId'] = your_id_value_here
You can then use this session variable in your jinja templates with something like the following:
<a class="/Task_Add/{{ session['UserId'] }}">Add Task</a>
(Note, if you are not already using session, you will need to import it with from Flask import session.)

Python renders wrong page using web.py

I am trying to teach myself Python. I have the following code in my controller.py file:
import web
urls = {
'/', 'home',
'/register', 'registerclick'
}
render = web.template.render("views/templates", base="MainLayout")
app = web.application(urls, globals())
# Classes/Routes
class home:
def GET(self):
return render.home()
class registerclick:
def GET(self):
return render.register()
if __name__ == "__main__":
app.run()
And this is the code in my MainLayout.html:
$def with (page)
$var css: static/css/bootstrap.css
$var js1: static/js/jquery-3.1.0.min.js static/js/bootstrap.js static/js/material.min.js static/js/ripple.min.js static/js/scripty.js
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CodeWizard</title>
$if self.css:
$for style in self.css.split():
<link rel="stylesheet" href="$style" />
</head>
<body>
<div id="app">
<div class="navbar navbar-info navbar-fixed-top">
<div class="navbar-header">
<a class="navbar-brand">CodeWizard</a>
</div>
<ul class="nav navbar-nav">
<li>
<a class="waves-effect" href="/">Home Feed<div class="ripple-container"></div></a>
</li>
<li>
Discover<div class="ripple-container"></div>
</li>
<li>
Profile<div class="ripple-container"></div>
</li>
<li>
Settings<div class="ripple-container"></div>
</li>
</ul>
<div class="pull-right">
Register
</div>
</div>
<br /><br />
$:page
</div>
$if self.js1:
$for script in self.js1.split():
<script src="$script"></script>
</body>
</html>
I have 2 additional files (home.html, and register.html) and I have bootstrap available (although that has nothing to do with my issue).
When I start the application and I open a browser and enter localhost:8080 as the url, MainLayout.html is loaded into the browser (which I expect) but the contents of register.html are loaded into $:page and I don't know why.
When I remove the second entry from the urls and remove the regnsterclick class from controller.py, the MainLayout.html page is loaded and nothing appears to be loaded into $:page.
Any ideas why the contents of register.html get presented? Any help is greatly appreciated.
Thanks.
By defining urls with braces, you made it a set, which is unordered. You need to define urls as a tuple which can be done using parentheses.
This answer explains it well: https://stackoverflow.com/a/46633252/2150542

web.py and how to use section blocks

I use web.py Templator for my project and using the render('templates', base="") I combine a base layout with a page specific layout (simplified).
view.py
render = web.template.render('templates',base='layout')
return render.index()
shared layout file
layout.html
$def with (content)
<html>
<head>
<title>$content.title</title>
</head>
<body>
$:content
</body>
</html>
page specific template
index.html
$def with (values)
$var title: Hello Kitty
<p>Hello $values, how are you doin?</p>
The solution I'm looking for is how to achieve the following
login.html
$def with (values)
$var title: Enter credentials
<form>
<p><input type="text" name="user_name"></p>
<p><input type="password" name="user_pwd"></p>
<p><button type="submit">Open the gates</button></p>
</form>
$block_begin
<script>
// When the form is submitted, check the required fields and inform user
// if any data is missing or looks weird
</script>
$block_end
</body>
</html>
My question is, how do I add the script to the login.html template but not the index.html template? I'm not interested in having to add all JS logic to all pages, I would like to add this $block_begin/$block_end so that it appears at the bottom of the layout.html like this
layout.html
$def with (content)
<html>
<head>
<title>$content.title</title>
</head>
<body>
$:content
$block_begin
$block_end
</body>
</html>
The $block_begin/$block_end was just something I came up with to better explain myself.
Just to be clear, template -> defwith sections is a grammar, not an example. To use templates, check http://webpy.org/docs/0.3/templetor for examples.
At a high level, you create templates similar to
=== templates/index.html ===
$def with(values)
$var title: Hello Kitty
<p>Hello $values, how are you doin?</p>
=== templates/layout.html ===
$def with(content)
<html>
<head>
<title>$content.title</title>
</head>
<body>
$:content
</body>
</html>
Then in your python you render the template, passing in any parameters specified in the template. ("values" in this example.) The named template (index.html) is render using the base (layout.html), and as you've discovered, content contains the rendered internal bit (the results of index) and is inserted into the base template, layout.
You're asking how to get some script into login.html, but not in index.html & that's easy: just add the javascript code into the login.html template.
=== login.html ===
$def with (values)
$var title: Enter credentials
<form>
...
</form>
<script>
window.addEventListener('load', function () {
// whatever javascript you want to execute on load.
// If using jQuery, you'll have to use $$('form') or jQuery('form') rather
// than $('form'), as dollar signs are special within the template.
});
</script>
Something more clever? Use content more fully. Anything you define using $var in your template gets put into $content in the base layout.
If you want to include login.js only when your login.html page is rendered, you could simple create a new content attribute. In login.html:
$var extra_js: js/login.js
Then, in your layout file conditionally load the value at the bottom (where we like to load scripts).
=== templates/layout.html ===
...
<body>
$:content
$if content.get('extra_js', None):
<script type="text/javascript" src="$content.extra_js"></script>
</body>
</html>
You can make your layout.html more and more powerful, parameterizing meta data, scripts, css files, etc. Just like you did with $content.title, and let your individual template files drive different parts of the overall layout.

Scan descendant template namespaces for particular attributes

I'm trying to understand the Version One - Use Namespace.attr example for accessing descendant attributes in Mako. I have the base page template in page.html, and the index page in index.html which inherits page.html. I want to allow page.html (and page that inherits it) to specify their own Javascript and CSS files to include and allow page.html to handle rendering them.
page.html:
<!DOCTYPE html>
<%namespace name="common" file="common.html"/>
<%
# Scan for scripts and styles to include.
include_scripts = []
include_styles = []
for ns in context.namespaces.values():
if hasattr(ns.attr, 'include_scripts'):
include_scripts.extend(ns.attr.include_scripts)
if hasattr(ns.attr, 'include_styles'):
include_styles.extend(ns.attr.include_styles)
%>
<html>
<head>
<title>${self.attr.title}</title>
% for style in include_styles:
${common.style(style)}
% endfor
% for script in include_scripts:
${common.script(script)}
% endfor
</head>
<body>
${next.main()}
</body>
</html>
common.html:
<%def name="script(src)">
<script type="application/javascript" src="%{src | h}"></script>
</%def>
<%def name="style(href)">
<link rel="stylesheet" type="text/css" href="${href | h}"/>
</%def>
index.html:
<%inherit file="page.html"/>
<%!
# Set document title.
title = "My Index"
# Set document scripts to include.
include_scripts = ['index.js']
# Set document styles to include.
include_styles = ['index.css']
%>
<%def name="main()">
<h1>${title | h}</h1>
</%def>
This all renders the following page:
<!DOCTYPE html>
<html>
<head>
<title>My Index</title>
</head>
<body>
<h1>My Index</h1>
</body>
</html>
The rendered page is missing the styles and javascript includes that I'm expecting which should be:
<!DOCTYPE html>
<html>
<head>
<title>My Index</title>
<script type="application/javascript" src="index.js"></script>
<link rel="stylesheet" type="text/css" href="index.css"/>
</head>
<body>
<h1>My Index</h1>
</body>
</html>
In page.html, if I print context.namespaces I get:
{('page_html', u'common'): <mako.runtime.TemplateNamespace object at 0x1e7d110>}
Which indicates that only the imported common.html template is available and but no descendant template namespaces which inherit from page.html. How do I iterate through the inheriting template namespaces and check their attributes? I know I can use next to get the next template namespace, but how do I get the next template namespace after that if it exists?
The code snippet in page.html to check descendent templates for the include_scripts and include_styles attributes has to traverse next of each descendant template namespace to get to the next. Using context.namespaces only appears to list the local namespaces.
import mako.runtime
# Scan for scripts and styles to include.
include_scripts = []
include_styles = []
# Start at the first descendant template.
ns = next
while isinstance(ns, mako.runtime.Namespace):
if hasattr(ns.attr, 'include_scripts'):
include_scripts.extend(ns.attr.include_scripts)
if hasattr(ns.attr, 'include_styles'):
include_styles.extend(ns.attr.include_styles)
# NOTE: If the template namespace does not have *next* set, the built
# in python function *next()* gets returned.
ns = ns.context.get('next')

Configurable head with chameleon load

When using chameleon, I can replace element from a base template using the concept of slot. Where you define a slot and fill it using another tag. As there is no container element in head, how can one add elements to head ? :
The Layout file
<html>
<head>
<div metal:define-slot="extra_head"></div>
</head>
<body>
...
</body>
</html>
The content template that need to specify extra head.
<html metal:use-macro="load: main.pt">
<div metal:fill-slot="extra_head">
<script type="text/javascript" src="http://example/script.js"></script>
</div>
...
</html>
This gets rendered in :
<html>
<head>
<div metal:fill-slot="extra_head">
<script type="text/javascript" src="http://example/script.js"></script>
</div>
</head>
<body>
...
</body>
</html>
But there's no container tag in head so how can one define a slot to add stuff in the head ?
There's an alternative to using tal:omit-tag (which I'm finding annoyingly confusing - more than once I spent many minutes trying to figure out why a certain tag does not appear in the output when it's clearly present in the template, only to find tal:omit-tag neatly tucked in the far corner): if you use xml tags with tal: and metal: namespaces they won't appear in the output:
<html>
<head>
<metal:my-slot define-slot="extra_head"></metal:my-slot>
</head>
<body>
...
</body>
</html>
and in the child template:
<metal:template use-macro="load: main.pt">
<metal:any-descriptive-name fill-slot="extra_head">
<script type="text/javascript" src="http://example/script.js"></script>
</metal:any-descriptive-name>
...
</metal:template>
Note how the template becomes much more readable and self-descriptive and does not contain weird things such as a <div> inside <head> :)
You also can omit tal: and metal: prefixes on attributes when using namespaced tags, so
<h1 tal:condition="..." tal:content="..." tal:omit-tag="">Hi there! Bogus content for added confusion!</h1>
becomes
<tal:greeting condition="..." content="..." />
To remove the tag one has to use tal:omit-tag :
In the content template, use :
<html metal:use-macro="load: main.pt">
<div metal:fill-slot="extra_head" tal:omit-tag="">
<script type="text/javascript" src="http://example/script.js"></script>
</div>
...
</html>
The div is not part of the result. Read the doc.

Categories

Resources