Related
I have a table : output _df (image in the question) .
Ienter image description here repetition of the same value for "PCR POS/Neg" consecutive in my "output_df".
If i have 3 results identiques consecutifs , more than 3 times in the output_df so i need to give an error message "WARNING" in my index.html
How i can do it ?
views.py
from django.shortcuts import render
from django.core.files.storage import FileSystemStorage
import pandas as pd
import datetime
from datetime import datetime as td
import os
from collections import defaultdict
from django.contrib import messages
import re
import numpy as np
def home(request):
#upload file and save it in media folder
if request.method == 'POST':
uploaded_file = request.FILES['document']
uploaded_file2 = request.FILES['document2']
if uploaded_file.name.endswith('.xls') and uploaded_file2.name.endswith('.txt'):
savefile = FileSystemStorage()
#save files
name = savefile.save(uploaded_file.name, uploaded_file)
name2 = savefile.save(uploaded_file2.name, uploaded_file2)
d = os.getcwd()
file_directory = d+'/media/'+name
file_directory2 = d+'/media/'+name2
cwd = os.getcwd()
print("Current working directory:", cwd)
results,output_df,new =results1(file_directory,file_directory2)
return render(request,"results.html",{"results":results,"output_df":output_df,"new":new})
else:
messages.warning(request, ' File was not uploaded. Please use the correct type of file')
return render(request, "index.html")
#read file
def readfile(uploaded_file):
data = pd.read_excel(uploaded_file, index_col=None)
return data
def results1(file1,file2):
results_list = defaultdict(list)
names_loc = file2
listing_file = pd.read_excel(file1, index_col=None)
headers = ['Vector Name', 'Date and Time', 'Test ID', 'PCR POS/Neg']
output_df = pd.DataFrame(columns=headers)
with open(names_loc, "r") as fp:
for line in fp.readlines():
line = line.rstrip("\\\n")
full_name = line.split(',')
sample_name = full_name[0].split('_mean')
try:
if len(re.split(r'(^[^\d]+)', sample_name[0])[2]) > 1:
sample_id = int(re.split(r'(^[^\d]+)', sample_name[0])[2])
else:
sample_id = int(re.split(r'(^[^\d]+)', sample_name[0])[2])
except:
sample_id = sample_name[0]
try:
if listing_file['Test ID'].isin([sample_id]).any():
line_data = listing_file.loc[listing_file['Test ID'].isin([sample_id])]
# The name of the file as it is shown in the folder
vector_name = line
# The data and the time of the taken sample
d_t = full_name[1].split('us_')[1].split('_')
date_time = td(int(d_t[0]), int(d_t[1]), int(d_t[2]), int(d_t[3]), int(d_t[4]), int(d_t[5]))
# Calculating the time frame from the swap to test of samples
date_index = list(line_data['Collecting Date from the subject'].iteritems())
for x in date_index:
if type(x[1]) is str():
date_time_obj = td.strptime(x[1], '%Y.%m.%d. %H:%M')
elif type(x[1]) is pd.Timestamp:
date_time_obj = x[1]
elif type(x[1]) is datetime.datetime:
date_time_obj = x[1]
frame_time = str(date_time - date_time_obj)
if date_time - date_time_obj > datetime.timedelta(hours=48):
results_list["List of samples with time frame over 48 :"].append(sample_id)
# The Test ID as it writen in the listing file
test_id = sample_id
# The PCR answer as it was written in the listing file
pcr_index = list(line_data['PCR Pos/Neg'].iteritems())
if len(pcr_index) > 1:
results_list["List of Samples with more than one attribute in the listing file:"].append(sample_id)
for x in pcr_index:
pcr_ans = x[1].strip()
values_to_add = {'Vector Name': vector_name,
'Date and Time': date_time,
'Test ID': test_id,
'PCR POS/Neg': pcr_ans,
'Time Frame': frame_time
}
row_to_add = pd.Series(values_to_add)
output_df = output_df.append(row_to_add, ignore_index=True)
else:
results_list["List of Samples not in the listing file:"].append(sample_name[0])
except:
print('The template name isnt good: {}'.format(sample_id))
output_df['Date and Time'] = pd.to_datetime(output_df['Date and Time'])
new = output_df.groupby([output_df['Date and Time'].dt.date, 'PCR POS/Neg']).size().unstack(fill_value=0)
return dict(results_list), output_df.to_html(), new.to_html()
index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html">
<head>
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}"/>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<link href='https://fonts.googleapis.com/css?family=Poppins' rel='stylesheet'>
</head>
<body id="ok" style=" width: 150; height: 100vh; background-size: cover;font-family: 'Poppins'; background-repeat:no-repeat; background-image: url('static/images/o.png'); ">
<br>
<br>
<nav class="navbar navbar-expand-lg navbar-white " style=" border-radius: 25px;box-shadow: inset 0 0 5px grey; margin:2em;background-color:#EDF1F6 ; 350px;">
<img src="static/images/mi2.png" style=" width: 350px; " >
<div class="container-fluid" style="text-align: center; margin: auto;">
<a class="navbar-brand" href="#"></a>
<button class="navbar-toggler" style="color:#0D4171;padding: 1px 1px;" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation" >
<span class="navbar-toggler-icon"></span>⇩</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav" style="text-align: center; margin: auto;">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<li class="nav-item" style="#DAE2EA" >
<label class="btn btn-outline" style=" color: #0D4171;border-radius: 25px; font-size: 21px; text-align: center;">
<i class="fa fa-cloud-upload" style="font-size: 1.5em;"></i> <br>Listing files (.xls) <input type="file" name="document" id="document" required="required">
</label>
<label class="btn btn-outline" style=" color: #0D4171; font-size: 21px;">
<i class="fa fa-cloud-upload" style="font-size: 1.5em;"></i> <br>File Names (.txt) <input type="file" name="document2" id="document2" required="required">
</label>
<br>
<div style="margin: auto;">
<br>
<button class="btn" style="background-color: #0D4171; border: none; ;color: white; padding: 10px 25px; text-decoration: none;
font-size: 16px;font:Poppins Medium; border-radius: 15px; margin-right:65px;" > Upload </button>
</div>
</li>
</form>
</ul>
{% block messages %}
{% if messages %}
{% for message in messages %}
{% endfor %}
{% endif %}
{% endblock %}
</div>
</div>
</nav>
{%block body%}{% endblock body%}
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</body>
</html>
<div class="">
<h1></h1>
<p></p>
<p></p>
</div>
{{variable}}
</body>
</html>
results.html
<!DOCTYPE html>
<html lang="en">
<head>
<link href='https://fonts.googleapis.com/css?family=Poppins' rel='stylesheet'>
<meta charset="UTF-8">
<title> Dashboard Result</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript">
$("#btnPrint").live("click", function () {
var divContents = $("#dvContainer").html();
var printWindow = window.open('', '', 'height=100,width=200');
printWindow.document.write('<html><head><title> ListingCheckPdf</title>');
printWindow.document.write('</head><body >');
printWindow.document.write(divContents);
printWindow.document.write('</body></html>');
printWindow.document.close();
printWindow.print();
});
</script>
</head>
<body id="ok" style="margin:0.5; padding:0.5em; width: auto;background-size: cover;font-family: 'Poppins'; height:auto; background-size: cover; background-repeat:no-repeat; background-image: url('static/images/o.png'); ">
<nav class="navbar navbar-expand-lg navbar-white " style=" border-radius: 25px; margin:2em;background-color:#EDF1F6 ; ">
<img src="static/images/mi3.png" style=" width: 250px; margin-left:1em;" >
<form id="form1">
<br>
<input type="button" style="background-color: #0D4171; border: none; color: white; padding: 8px 18px; text-align: center; text-decoration: none; display: inline-block; font-size: 15px; margin-left:30px; font-family: 'Poppins'; border-radius: 25px;" value="Download PDF" id="btnPrint" /><br><br><br>
<div class="container-fluid" id="dvContainer" style="width: 900px;height: 900px; border-radius:15px; background-color:white; margin:auto; box-shadow: inset 0 0 5px grey;border-radius: 10px; overflow: scroll; /* showing scrollbars */" >
<style>table, td, th { margin-left: auto; margin-right: auto; border: 1px solid black; width: 600px; text-align:center; align-items: center;} </style> <br>
<div>
{% autoescape off %}{{ new }}{% endautoescape %}
</div><br><br>
<div style="color: hidden; margin: 30px; font: Poppins; font-size: 17px">
{% for key, value in results.items %}<br>
{{ key }}<br>
{% for elem in value %}
<div style="margin-left:50px" >
- {{elem }} <br></div>
{% endfor %}
{% endfor %}</div><br><br><br><br><br>S
<div>{% autoescape off %}{{ output_df }}{% endautoescape %}</div>
</div>
</form>
</body>
</html>
How do you do an ajax post after a successful submit form post. I want to take the input submitted on the form, do some calculations based on that input, and display the results on the front-end without the page refreshing.
FLASK
#app.route('/', methods=['GET', 'POST'])
def app_home():
if request.method == 'POST':
input_amount = request.form['input_amount']
input_amount = float(input_amount)
amount1 = input_amount * 12
amount2 = input_amount * 10
return render_template("index.html", amount1=amount1,amount2=amount2,)
return render_template("index.html")
if __name__ == '__main__':
app.run(debug=True)
index.html
<form method="post">
<div class="mb-3">
<label>Enter amount</label>
<input name = "input_amount" type="text" class="form-control" placeholder="amount">
</div>
<button type="submit" class="btn btn-success">Submit</button>
</form>
<div class="container">
<p id = "response">result is: ${{amount1}}</p>
<p id = "response">result is: ${{amount2}}</p>
</div>
AJAX request
<script>
$(document).ready(function () {
$('form').on('submit', function (event) {
$.ajax({
data: { input_amount : input_amount},
type: 'POST',
url: '/'
})
.done(function (data) {
$('#response').text(data.output).show();
});
event.preventDefault();
});
});
</script>
As per the documentation the correct way is not using a form. Truth be told you don't want to submit a form right? You just want to pass the input values.
So I tried out the documentation code (since i'm also studing this "ajax + flask connection" for my app) and this should answer your question. Made a button class since you (and I) prefer button to a link.
app.py
from flask import Flask, jsonify, render_template, request
app = Flask(__name__)
#app.route('/_add_numbers')
def add_numbers():
a = request.args.get('a', 0, type=int)
b = request.args.get('b', 0, type=int)
return jsonify(result=a + b)
#app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug = True)
index.html
<!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" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$SCRIPT_ROOT = {{ request.script_root|tojson }};
</script>
<title>Document</title>
<style>
.button {
background-color: #5b4caf;
border: none;
color: white;
padding: 0.75rem 0.75rem;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 14px;
border-radius: 3px;
}
</style>
</head>
<body>
<h1>jQuery Example</h1>
<p>
<input type="text" size="5" name="a" /> +
<input type="text" size="5" name="b" /> = <span id="result">?</span>
</p>
<p>
Calculate server side
<script>
$(function () {
$("a#calculate").bind("click", function () {
$.getJSON(
$SCRIPT_ROOT + "/_add_numbers",
{
a: $('input[name="a"]').val(),
b: $('input[name="b"]').val(),
},
function (data) {
$("#result").text(data.result);
}
);
return false;
});
});
</script>
</p>
</body>
</html>
I have created a simple Flask app which renders a template 'index.html' and in that HTML I am attempting to list various plots as a sort of dashboard-style webpage with other content. I know the basics of Flask and Dash though am not using Dash as I want to have more control over the HTML/CSS hence using Flask to create a website to embed the graphs using Plotly.
So far I've had no luck with any of the official documentation or any medium.com or suchlike articles. The closest I have come to is this answer: Embedding dash plotly graphs into html
However, it isn't working when I run my app and the browser launches in localhost. Instead it just gives me a lot of text which is clearly the plotly figure, but it isn't turning into a graph.
Here is all my py/html/css even if the navbar stuff isn't relevant; just in case (I am still learning so I'm sure there will be some better ways to do things..)
Thanks for any help.
DataFrame class which grabs the latest Coronavirus data and returns as pandas.dataframe:
import pandas as pd
import requests
class DataFrame:
"""
Class which grabs the data live from the ECDC and returns it in a pandas dataframe
"""
def __init__(self):
"""
Creating the pandas dataframe of the ECDC JSON data
"""
self.url = "https://opendata.ecdc.europa.eu/covid19/casedistribution/json"
self.file = requests.get(self.url).json()
self.file = self.file['records']
self.df = pd.DataFrame(data=self.file)
def converter(self):
"""
Converting the dtypes from object to int for ints, and date to date
Also renames the columns to more visual-friendly names
:return: None
"""
self.df['cases'] = self.df['cases'].astype(int)
self.df['deaths'] = self.df['deaths'].astype(int)
self.df['popData2018'] = self.df['popData2018'].astype(str).replace('', 0).astype(int)
self.df['dateRep'] = self.df['dateRep'].to_timestamp
cols_rename = 'date day month year cases deaths country geo_id country_id population continent'.split()
cols_rename = [s.capitalize() for s in cols_rename]
self.df.columns = cols_rename
def return_df(self):
"""
:return: pandas DataFrame
"""
self.converter()
return self.df
app.py
from plotly.offline import plot
import plotly.graph_objects as go
from dataframe.dataframe import DataFrame
from flask import Flask, render_template, redirect, request, url_for
app = Flask(__name__)
def graph_maker():
df = DataFrame().return_df()
data = []
for continent in df['Continent'].unique():
df_filt = df[df['Continent'] == continent]
data.append(go.Scatter(x=df_filt["Cases"],
y=df_filt["Deaths"],
mode='markers',
text=df_filt['Country'],
name=continent))
layout = go.Layout(title="Deaths (Y) v Cases (X) by continent")
fig = go.Figure(data=data, layout=layout)
return plot(figure_or_data=fig,
include_plotlyjs=False,
output_type='div')
#app.route('/')
def index():
graph = graph_maker()
return render_template('index.html',
graph=graph)
if __name__ == '__main__':
app.run(debug=True)
index.html
{% extends "navbar.html" %}
<head>
<meta charset="UTF-8">
<link type="text/css" rel="stylesheet" href="..\static\master.css">
<link href="https://fonts.googleapis.com/css2?family=Maven+Pro&display=swap" rel="stylesheet">
<!-- Plotly.js -->
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
{% block nbar %}
<body>
<div class="global-box" id="global-stats">
<h1>Global charts</h1>
<p>Title here</p>
<ul class="global-box-ul">
<li class="global-box-ul-li">
{{ graph }}
</li>
<li class="global-box-ul-li">
Another chart here
</li>
</ul>
</div>
</body>
{% endblock %}
navbar.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>C19DB</title>
<meta charset="UTF-8">
<link type="text/css" rel="stylesheet" href="..\static\master.css">
<link href="https://fonts.googleapis.com/css2?family=Maven+Pro&display=swap" rel="stylesheet">
</head>
<nav class="navbar">
<div class="logo">c19db</div>
<div class="list">
<ul class="navbar_items">
<li class="navbar_item">Dashboard</li>
<li class="navbar_item">About</li>
<li class="navbar_item">Register</li>
</ul>
</div>
</nav>
{% block nbar %}
{% endblock %}
</html>
master.css
html, body {
font-family: 'Maven Pro';
height: 700px;
margin: 0;
}
.navbar {
background: rgb(237, 232, 232);
vertical-align: middle;
}
.logo {
vertical-align: middle;
display: inline-block;
color: rgb(196, 69, 69);
font-size: 50px;
width: 250px;
padding: 5px 15px 5px 15px;
}
.list{
vertical-align: middle;
display: inline-block;
width: calc(100% - 285px);
text-align: right;
}
.navbar_items {
list-style: none;
font-size: 20px;
color: rgb(61, 61, 61)
}
.navbar_item{
display: inline-block;
padding: 5px 15px 5px 15px;
}
a {
text-decoration: none;
}
.navbar_item > a{
display: inline-block;
padding: 5px 15px 5px 15px;
color: rgb(61, 61, 61);
}
.navbar_item > a:hover {
display: inline-block;
padding: 5px 15px 5px 15px;
color: rgb(196, 69, 69);
}
.footer, .footer a {
position: relative;
background: rgb(237, 232, 232, 0.2);
width: 100%;
color: rgb(61, 61, 61, 0.2);
text-align: center;
}
span {
font-weight: bold;
}
.global-box {
text-align: center;
border: 2px black solid;
list-style: none;
margin: auto;
}
.global-box > h1, .global-box > p {
margin: 1px;
}
ul {
display: contents;
}
.global-box-ul-li {
display: inline-block;
border: 2px lightblue solid;
list-style: none;
margin: auto;
width: 48%;
height: 100%;
}
Thank you for any help!
I have solved this problem.
Nutshell:
Create a chart
Call pyo.plot() as normal passing through the fig, output_type='div' and include_plotlyjs=False
Have that output to a variable passed through Markup() (import from flask)
Have the Markup(variable) passed through the render_template like you would a form
Have the variable rendered in the html using {{ jinja template }}
First, create your Plotly chart like normal. I will not give a whole example but just the key points. I create charts in functions for import and use in multiple pages if necessary. In this case, it's necessary because the chart must be assigned to a variable.
def my_bar_chart():
*snip irrelevant*
my_bar_chart = pyo.plot(fig, output_type='div', include_plotlyjs=False)
return Markup(my_bar_chart)
Now import your function to your app.py / wherever your views are and pass it through render template as you would any form, for example.
Here is an example:
def my_page():
my_bar_chart_var = my_bar_chart()
return render_template('my_page.html',
bar_chart_1=my_bar_chart_var)
Then on the html for that page simply pass through bar_chart_1 in a jinja template like so:
{{ bar_chart_1 }}
And done.
I have a plotly scatter, but it's not displayed by flask
I took it from examples from internet
Result of my work looks like that:
And here is my code:
plotly_test.py
from flask import Flask, render_template
import json
import plotly
from plotly import graph_objs as go
import numpy as np
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def kek():
t = np.linspace(0, 10, 100)
fig = go.Figure()
fig.add_trace(go.Scatter(
x=t, y=np.sin(t),
name='sin',
mode='markers',
marker_color='rgba(152, 0, 0, .8)'
))
fig.add_trace(go.Scatter(
x=t, y=np.cos(t),
name='cos',
marker_color='rgba(255, 182, 193, .9)'
))
fig.update_traces(mode='markers', marker_line_width=2, marker_size=10)
fig.update_layout(title='Styled Scatter',
yaxis_zeroline=False, xaxis_zeroline=False)
data = [fig]
graphJSON = json.dumps(data, cls=plotly.utils.PlotlyJSONEncoder)
return render_template('test1.html', graphJSON=graphJSON)
if __name__ == '__main__':
app.run()
And my html with styles and script:
test1.html
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
.header{
text-align: center;
background-color: rgb(136, 185, 229);
height: 70px;
line-height: 70px;
}
.chart{
margin-top: 30px;
text-align: center;
}
</style>
</head>
<body>
<div class="header">
<h2>
Plotly Chart Demo
</h2>
</div>
<div id="chart" class="chart">
</div>
</body>
<!-- D3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<!-- Plotly.js -->
<script src="https://d14fo0winaifog.cloudfront.net/plotly-basic.js"></script>
<script type="text/javascript">
var graphs = {{ graphJSON|safe }};
Plotly.plot('chart', graphs, {});
</script>
</html>
Can you explain me what do I do wrong?
Scatter works good without flask, but it doesn't with it!
js concole
Put this in the head:
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
And delte this part:
<!-- D3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<!-- Plotly.js -->
<script src="https://d14fo0winaifog.cloudfront.net/plotly-basic.js"></script>
I'm trying to develop an app for Google App Engine using Cherrypy.
I'm using a custom tool to apply templates with. Part of the output is a html css stylesheet declaration. I can get cherrypy to find and load the css file no problem, the problem is the template gets applied to the css output.
Here's my code I'm using
import cherrypy
from lib.tools.template import HamlTool
engine = cherrypy.engine
from lib.plugin.template import MakoTemplatePlugin
engine.mako = MakoTemplatePlugin(engine, os.path.join(os.path.dirname(__file__), 'templates'))
engine.mako.subscribe()
class Root(object):
exposed = True
#tools.encode()
#tools.template(template='index.haml')
def GET(self):
return 'Hello I like CherryPy!'
cherrypy.tools.template = HamlTool()
conf = {
'/': {
'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
'tools.sessions.on': True,
},
'/assets/css/bootstrap-responsive.min.css' : {
'tools.staticfile.on': True,
'tools.staticfile.filename' : os.path.join(os.path.dirname(__file__), 'assets/css/bootstrap-responsive.min.css')
}
}
root = Root()
app = cherrypy.tree.mount(root, '/', config=conf)
run_wsgi_app(app)
This is the HamlTool code
import cherrypy
import haml
import mako.lookup
class HamlTool(cherrypy.Tool):
def __init__(self):
cherrypy.Tool.__init__(self, 'before_finalize',
self._render,
priority=0)
def _render(self, template=None):
if cherrypy.response.status > 399:
return
# retrieve the data returned by the handler
data = {'data':''.join(cherrypy.response.body), 'title': 'Hello there'} or {}
try:
template = cherrypy.engine.publish("lookup-template", template).pop()
except:
template = None
print
print 'template: ', template
if template:
# dump the template using the dictionary
cherrypy.response.body = str(template.render(**data))
And the MakoTemplatePlugin code
from cherrypy.process import plugins
import mako.lookup
import haml
class MakoTemplatePlugin(plugins.SimplePlugin):
def __init__(self, engine, template_dir='templates'):
super(MakoTemplatePlugin, self).__init__(engine)
self.template_dir = template_dir
print 'MakoTemplatePlugin: init', self.template_dir
self.lookup = mako.lookup.TemplateLookup(
directories=self.template_dir,
preprocessor=haml.preprocessor
)
self.bus.subscribe('lookup-template', self.get_template)
def start(self):
print 'MakoTemplatePlugin: start', self.template_dir
self.lookup = mako.lookup.TemplateLookup(
directories=self.template_dir,
preprocessor=haml.preprocessor
)
self.bus.subscribe('lookup-template', self.get_template)
def stop(self):
self.bus.unsubscribe('lookup-template', self.get_template)
self.lookup = None
def get_template(self, name):
print 'MakoTemplatePlugin: lookup template', name, self.template_dir
return self.lookup.get_template(name)
The base template
!!! 5
%html(lang="en")
%head
%title= title
%meta(name="viewport", content="width=device-width, initial-scale=1.0")
%link(href="/assets/css/bootstrap-responsive.min.css", rel="stylesheet")
%body
.container-fluid=self.body()
%script(src="http://code.jquery.com/jquery.js")
%script(src="/assets/js/bootstrap-responsive.min.js")
The actual template which inherits from base
<%inherit file="base.haml"/>
.row-fluid
.span12-fluid=data
The output from the root is fine
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello there</title>
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
<link href="/assets/css/bootstrap-responsive.min.css" rel="stylesheet" />
</head>
<body>
<div class="container-fluid">
<div class="row-fluid">
<div class="span12-fluid">Hello I like CherryPy!</div>
</div>
</div>
<script src="http://code.jquery.com/jquery.js"></script>
<script src="/assets/js/bootstrap-responsive.min.js"></script>
</body>
</html>
but when you have a look at the output from the css you get
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello there</title>
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
<link href="/assets/css/bootstrap-responsive.min.css" rel="stylesheet" />
</head>
<body>
<div class="container-fluid">
<div class="row-fluid">
<div class="span12-fluid">/*!
* Bootstrap Responsive v2.3.1
*
* Copyright 2012 Twitter, Inc
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Designed and built with all the love in the world #twitter by #mdo and #fat.
*/.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}#media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}#media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}#media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}#media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}#media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}#media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}#media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}#media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}#media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}}
</div>
</div>
</div>
<script src="http://code.jquery.com/jquery.js"></script>
<script src="/assets/js/bootstrap-responsive.min.js"></script>
</body>
</html>
What have I done wrong and how do I prevent the tenmplate from being applied to css and javascript files referenced by this page?
UPDATE:
I forgot to mention that I already tried disabling the template plugin on the static files by putting
'tools.template.on':False
in the static files part of the config. The only way I seem to be able to stop this is to remove the templates decorator all together. The only problem with that is the template will not be applied and the output will not include the html which includes the desired css import.
In your static sections, simply disable the tool:
tools.template.on: False