Here's another question about Django.
I have this code:
views.py
cursor = connections['cdr'].cursor()
calls = cursor.execute("SELECT * FROM cdr where calldate > '%s'" %(start_date))
result = [SQLRow(cursor, r) for r in cursor.fetchall()]
return render_to_response("cdr_user.html",
{'calls':result }, context_instance=RequestContext(request))
I use a MySQL query like that because the database is not part of a django project.
My cdr table has a field called duration, I need to divide that by 60 and multiply the result by a float number like 0.16.
Is there a way to multiply this values using the template tags? If not, is there a good way to do it in my views?
My template is like this:
{% for call in calls %}
<tr class="{% cycle 'odd' 'even' %}"><h3>
<td valign="middle" align="center"><h3>{{ call.calldate }}</h3></td>
<td valign="middle" align="center"><h3>{{ call.disposition }}</h3></td>
<td valign="middle" align="center"><h3>{{ call.dst }}</h3></td>
<td valign="middle" align="center"><h3>{{ call.billsec }}</h3></td>
<td valign="middle" align="center">{{ (call.billsec/60)*0.16 }}</td></h3>
</tr>
{% endfor %}
The last is where I need to show the value, I know the "(call.billsec/60)*0.16" is impossible to be done there. I wrote it just to represent what I need to show.
You can do it on three different layers:
Database level. SQL is a powerful language capable of mathematics. You could write your equation in the select part of your query. In your case, that should be along the lines SELECT (duration/60*0.16) FROM cdr;. Examples can be found here and on Google. Note that in this case, stress (algorithm complexity) is put on the MySQL server process and not the Python process.
View level. In your example, just before your return, you could loop over every element of your result variable to modify its value. You can follow the example that was given by Lie Ryan for this level.
Template level. This is done by a custom filter. You can write your custom filter as written in the documentation and pipe your template variable through this filter in order to get the desired value.
Something along these lines would represent a custom filter applicable on your template(s):
#register.filter
def customFilter(value):
return value / 60.0 * 0.16
You would then use it this way in your template, after {% load %}-ing the custom filter (read the documentation for more implementation information):
{{ billsec|customFilter }}
If the math operations are not too complex I normally use custom template tags. Add operation is already available as a template tag and I use the below snippet in my project for multiplication, subtraction and division respectively. Put this code inside a .py file inside your app/templatetags location and also add a __init__.py in there.
from django import template
#Django template custom math filters
#Ref : https://code.djangoproject.com/ticket/361
register = template.Library()
def mult(value, arg):
"Multiplies the arg and the value"
return int(value) * int(arg)
def sub(value, arg):
"Subtracts the arg from the value"
return int(value) - int(arg)
def div(value, arg):
"Divides the value by the arg"
return int(value) / int(arg)
register.filter('mult', mult)
register.filter('sub', sub)
register.filter('div', div)
EDIT: the following answer is totally wrong, since I thought OP was using sqlite. MySQL has its own way of wrapping things into dictionary, see far below.
You can subclass sqlite3.Row and write your own "computed field":
class MyRow(sqlite3.Row):
def comp_billsec(self):
return (self['billsec'] / 60) * 0.16
cursor = ...
cursor.row_factory = MyRow
for r in cursor.execute('...'):
print r['billsec'], r.comp_billsec()
note that our comp_billsec is accessed using method call syntax, while sqlite3.Row factory provides access through dictionary syntax. This discrepancy would disappear in django template since inside django template, dictionary access and zero-argument function call have the same syntax, so you can do {{ call.billsec }} and {{ call.comp_billsec }}.
EDIT: In MySQL, you can insert computed values in the view along the lines of:
cursor = connections['cdr'].cursor(cursorclass=MySQLdb.cursors.DictCursor)
calls = cursor.execute("...")
result = [r + dict(comp_billsec=r['billsec'] / 60 * 0.16) for r in cursor.fetchall()]
return render_to_response("cdr_user.html",
{'calls':result }, context_instance=RequestContext(request))
Additionaly, you should use parameterized query (note the comma instead of %):
cursor.execute("SELECT * FROM cdr where calldate > '%s'", (start_date,))
Your previous code is subject to SQL injection security issue since you're interpolating start_date into the SQL query directly. If start_date contains ' OR 1 OR ', for example, your query will be interpolated as SELECT * FROM cdr where calldate > '' OR 1 OR '' which will select all rows in the table; it could be even worse.
Related
I am trying to return two items to an html file in Flask and am having trouble figuring out the best way to do it.
The two operative lines Flask is pulling from in a separate file are:
# trader_db = Blotter(1000000, collection)
cash = self.cash + df['Value'].sum() # trader_db.cash
return df.to_html('templates/pnlstmt.html') # trader_db.pnl(collection)
with this code:
#app.route("/pl")
def show_pl():
cash = trader_db.cash
trader_db.pnl(collection)
return render_template('pnlstmt.html'), cash
I get the expected P&L
Symbol Position
AAPL 350.0
AMZN 1000.0
GOOG 350.0
But the cash isn't displayed.
Is there a way I can get show_pl() to display both objects?
I tried to make cash a DataFrame and concatenate but that threw an error.
The general idea is to separate "logic" from "presentation". Using python function you calculate values. And using template system you structure it in a presentable html view.
I wrote simple example that might be helpful for you:
First, we calculate data (I have a stub here) and pass them to the template context as variables:
from flask import app, render_template
import pandas as pd
main = app.Flask("app")
#main.route('/pnl')
def pnl():
df = pd.DataFrame([["AAPL","AMZN","GOOG"], [350.0,1000.0,350.0]], index=["Symbol","Position"]).T
cash = 100000
# passing data to the template
return render_template("pnl.html", data=df, cash=cash)
main.run(port=8889)
Second, we create template which "renders" our data into html. This is the content of pnl.html file:
<table>
{% for ind,row in data.iterrows() %}
<tr><td>{{ind}}</td><td>{{row["Symbol"]}}</td><td>{{row["Position"]}}</td></tr>
{% endfor %}
</table>
<h2>Total cash: {{ cash }}</h2>
This is a complete code to launch and test it.
I have a page with a list of items which includes their id, name, price and stock level. This information is gotten from a SQLite3 database and entered onto the page in a table. The table also has a column where the user can add or remove stock of the item.
This code shows a section of the table:
% for i in items:
<tr>
<th scope="row">{{i[0]}}</th>
<td>{{i[1]}}</td>
<td>{{i[2]}}</td>
<td>{{i[3]}}</td>
<td><form method="post" action="/worker"><input type="number" name="newStock.{{i[0]}}"><input style="margin-left: 5px" type="submit" Value="Submit"></form></td>
</tr>
% end
And here is the Python bottle code for this page
#route('/worker', method='GET')
def workerPage1():
return template('worker', items=store.printItems(2)) # 1 prints out for shoppers, 2 prints out for workers.
#route('/worker', method='POST')
def workerPage2():
# allows to receive ItemId
for k in request.forms:
if k.startswith('newStock.'):
itemId = k.partition('.')[-1]
numStock = request.forms.get(k)
store.updateStock(itemId,numStock) # this accesses the database, updating the stock level
return template('worker', items=store.printItems(2))
The problem I am getting, is that when I enter the stock to be added, say for example '8' it does it fine. But then when I refresh the page, it adds another 8 onto it. So if it was at 22 and then I click submit to add the stock, it would go to 30 and then when I refreshed the page it would go to 38, etc.
Any idea on how to stop this from happening?
Thanks.
Instead of return template('worker', items=store.printItems(2)) in workerPage2(), I used return redirect('worker'). Works as I wanted.
Is there a way to display the name/content/functions of all attributes of a given object in a jinja template. This would make it easier to debug a template that is not acting as expected.
I am building a website using the hyde framework and this would come in quite handy since I am still learning the intricacies of both jinja and hyde.
Originally, I had thought it would work to use the attr filter, but this seems to require a name value. I would like to to not have to specify the name in order to get all available attributes for the object.
Some google searching showed django syntax looks like the following, but I am not familiar with django so this may only apply to database items. Long story short, I would like a method that works kind of like this for any object named obj
{% for field, value in obj.get_fields %}
{{ field }} : {{ value }} </br>
{% endfor %}
final solution:
#jayven was right, I could create my own jinja2 filter. Unfortunately, using the stable version of hyde (0.8.4), this is not a trivial act of having a filter in the pythonpath and setting a simple yaml value in the site.yaml file (There is a pull-request for that). That being said, I was able to figure it out! So the following is my final solution which ends up being very helpful for debugging any unkown attributes.
It's easy enough to create site-specific hyde extensions just create a local python package with the following directory tree
hyde_ext
__init__.py
custom_filters.py
Now create the extension:
from hyde.plugin import Plugin
from jinja2 import environmentfilter, Environment
debug_attr_fmt = '''name: %s
type: %r
value: %r'''
#environmentfilter
def debug_attr(env, value, verbose=False):
'''
A jinja2 filter that creates a <pre> block
that lists all the attributes of a given object
inlcuding the value of those attributes and type.
This filter takes an optional variable "verbose",
which prints underscore attributes if set to True.
Verbose printing is off by default.
'''
begin = "<pre class='debug'>\n"
end = "\n</pre>"
result = ["{% filter escape %}"]
for attr_name in dir(value):
if not verbose and attr_name[0] == "_":
continue
a = getattr(value, attr_name)
result.append(debug_attr_fmt % (attr_name, type(a), a))
result.append("{% endfilter %} ")
tmpl = Environment().from_string("\n\n".join(result))
return begin + tmpl.render() + end
#return "\n\n".join(result)
# list of custom-filters for jinja2
filters = {
'debug_attr' : debug_attr
}
class CustomFilterPlugin(Plugin):
'''
The curstom-filter plugin allows any
filters added to the "filters" dictionary
to be added to hyde
'''
def __init__(self, site):
super(CustomFilterPlugin, self).__init__(site)
def template_loaded(self,template):
super(CustomFilterPlugin, self).template_loaded(template)
self.template.env.filters.update(filters)
To let hyde know about the extension add hyde_ext.custom_filters.CustomFilterPlugin to the "plugins" list of the site.yaml file.
Lastly, test it out on a file, you can add this to some random page {{resource|debug_attr}} or the following to get even the underscore-attributes {{resource|debug_attr(verbose=True)}}
Of course, I should add, that it seems like this might become much easier in the future whenever hyde 1.0 is released. Especially since there is already a pull request waiting to implement a simpler solution. This was a great way to learn a little more about how to use jinja and hyde though!
I think you can implement a filter yourself, for example:
from jinja2 import *
def show_all_attrs(value):
res = []
for k in dir(value):
res.append('%r %r\n' % (k, getattr(value, k)))
return '\n'.join(res)
env = Environment()
env.filters['show_all_attrs'] = show_all_attrs
# using the filter
tmpl = env.from_string('''{{v|show_all_attrs}}''')
class Myobj(object):
a = 1
b = 2
print tmpl.render(v=Myobj())
Also see the doc for details: http://jinja.pocoo.org/docs/api/#custom-filters
How do I persuade Jinja2 to not print "None" when the value is None?
I have a number of entries in a dictionary and I would like to output everything in a single loop instead of having special cases for different keywords. If I have a value of None (the NoneType not the string) then the string "None" is inserted into the template rendering results.
Trying to suppress it using
{{ value or '' }} works too well as it will replace the numeric value zero as well.
Do I need to filter the dictionary before passing it to Jinja2 for rendering?
In new versions of Jinja2 (2.9+):
{{ value if value }}
In older versions of Jinja2 (prior to 2.9):
{{ value if value is not none }} works great.
if this raises an error about not having an else try using an else ..
{{ value if value is not none else '' }}
Another option is to use the finalize hook on the environment:
>>> import jinja2
>>> e = jinja2.Environment()
>>> e.from_string("{{ this }} / {{ that }}").render(this=0, that=None)
u'0 / None'
but:
>>> def my_finalize(thing):
... return thing if thing is not None else ''
...
>>> e = jinja2.Environment(finalize=my_finalize)
>>> e.from_string("{{ this }} / {{ that }}").render(this=0, that=None)
u'0 / '
Default filter:
{{ value|default("", True) }}
A custom filter can solve the problem. Declare it like this:
def filter_suppress_none(val):
if not val is None:
return val
else:
return ''
Install it like this:
templating_environment.filters['sn'] = filter_suppress_none
Use it like this:
{{value|sn}}
According to this post from the Pocco Mailing List: https://groups.google.com/d/msg/pocoo-libs/SQ9ubo_Kamw/TadIdab9eN8J
Armin Ronacher (creater of Jinja2/Flask, etc...) recommends the following "pythonic" snippet:
{{ variable or 0 }} {{ variable or '' }}
The notion here being that once again, explicit is preferable to implicit.
Edit: The selected answer is definitely the correct one. I haven't really come across a situation where a template variable would be either a string or the numeric zero, so the above snippets might help reduce the code noise in the template.
I'm trying to use an ajax search slice for my website that I found here: http://www.web2pyslices.com/slices/take_slice/51
But for some reason I keep getting the error:
IndexError: list index out of range
Here is my version of the code:
default.py (controller)
def index():
listings = db().select(db.listing.ALL, orderby=db.listing.first_name)
return dict(listings=listings, livesearch=livesearch())
def livesearch():
partialstr = request.vars.values()[0]
query = db.listing.title.like('%'+partialstr+'%')
listings = db(query).select(db.listing.title)
items = []
for (i,listing) in enumerate(listings):
items.append(DIV(A(listing.title, _id="res%s"%i, _href="#", _onclick="copyToBox($('#res%s').html())"%i), _id="resultLiveSearch"))
return TAG[''](*items)
livesearch.html (view, which I'm {{including}} in the layout.html
<input type="text" id="search" name="search" autocomplete="off" onkeyup="getData(this.value);" /><br />
<div id="ajaxresults"></div>
db.py (model)
db.define_table(auth.settings.table_user_name,
Field('first_name'),
Field('last_name'),
Field('email'),
Field('password','password', length=512, readable=False, label='Password'),
Field('title'),
Field('photo','upload'),
Field('bio','text'),
Field('phone'), # Contact details
Field('website'),
Field('address'),
Field('registration_key', length=512,
writable=False, readable=False, default=''),
Field('reset_password_key', length=512,
writable=False, readable=False, default=''),
Field('registration_id', length=512,
writable=False, readable=False, default=''),
)
listing = db[auth.settings.table_user_name]
Any help would be very very greatly appreciated, cause I've been wracking my brains on it for days now (because I'm extremely new to programming)
Thanks!
def index():
listings = db().select(db.listing.ALL, orderby=db.listing.first_name)
return dict(listings=listings, livesearch=livesearch())
You don't want to return livesearch from the index function. According to the slice you referenced, the livesearch function should be called via Ajax from your index page.
def livesearch():
partialstr = request.vars.values()[0]
I know the above line is taken directly from the slice, but a better (and more typical way) to access the value of the posted variable is:
partialstr = request.vars.partialstr if request.vars else None
Note, the above syntax will return None if there are no request.vars or if request.vars.partialstr doesn't exist, so it won't generate an error.
Also, request.vars will be None whenever there are no request variables, so you can always test for request variables with:
if request.vars:
Finally, you may be interested in web2py's built-in auto-complete widget (though I think there may be some problems with it in IE, for which a fix is in the works).
If the following is your index() code:
def index():
listings = db().select(db.listing.ALL, orderby=db.listing.first_name)
return dict(listings=listings, livesearch=livesearch())
then, if you visit index.html page and livesearch() will be called, but at this time, request.vars.values() is empty, so IndexError raised.
Don't call livesearch() in index(), and use ajax to post search word to livesearch.html, and web2py will call livesearch(), and request.vars.values()[0] is the search word.