Have a flask wtforms select field and trying to incorporate htmx ajax call, which has dashes in data attributes so I found a solution on SO like the following:
{{ form.dia(class="form-select", **{'hx-post': "/pulleys/{{pulley_id}}/hub_type", 'hx-target': "#hub-shaft-selection", 'hx-swap': "innerHTML"}) }}
but the {{pulley_id}} doesn't get parsed by the template, I guess it's already inside another {{ }}.
Is there a way to build the dynamic part as shown above so it ends up as
'hx-post'="/pulleys/1/hub_type"
when fully rendered for pulley_id=1
If pulley_id is a variable either inside a loop or passed into render_template your should be able to format the string:
{{ form.dia(class_="form-select", **{'hx-post': "/pulleys/%s/hub_type"|format(pulley_id), 'hx-target': "#hub-shaft-selection", 'hx-swap': "innerHTML"}) }}
Note: you also want class_ not class if you're trying to set the HTML class attribute.
I've created a custom filter but my Flask server is getting an internal error.
#app.template_filter('doSomething')
def doSomething(input):
print(input)
return input
HTML
<p>{{ doSomething('Test') }}</p>
Error
jinja2.exceptions.UndefinedError: 'doSomething' is undefined
After some searching, trial and error, this is the only one that seems to work for me:
def doSomething(input):
print(input)
return input
app.jinja_env.globals.update(doSomething=doSomething)
In the documentation it says :doSomethingWith({{ user.username|tojson|safe }}); which means that the user.username object will be json serialised and then passed to the doSomethingWith which is a JavaScript function;not like {{doSomethingWith(user.username|tojson|safe);}} you used in your example which looks like you are trying to explicitly call a python function from the template, so try this and if you still have any troubles tell us more about what exactly you're trying to achieve.
Just to make this answer a bit useful while also addressing the question, I'll show a custom filter function for which I had a need. You can use the .app_template_filter() decorator method on your Flask app to effectively "register" the new template filter function. Once it's registered you can use it on any template within the context of your app or blueprint.
If you're using blueprints, in your controller you'd do something like this:
#some_blueprint.app_template_filter()
def utcToStrFilter(someUTCFloat):
try:
shiftedDateStr = datetime.strftime(datetime.fromtimestamp(someUTCFloat), "%Y-%m-%d %H:%M:%S")
return shiftedDateStr
except:
return ""
If you're not using blueprints then your decorator would be:
#app.app_template_filter()
or
#current_app.app_template_filter()
In any case, then in your template you just use it like a regular jinja filter:
{{ something.fileSavetimeUTC | utcToStrFilter }}
The key thing is to make the app aware of the function, which is what .app_template_filter() is for.
Using Jinja2, how do I format a date field? I know in Python I can simply do this:
print(car.date_of_manufacture.strftime('%Y-%m-%d'))
But how do I format the date in Jinja2?
There are two ways to do it. The direct approach would be to simply call (and print) the strftime() method in your template, for example
{{ car.date_of_manufacture.strftime('%Y-%m-%d') }}
Another, sightly better approach would be to define your own filter, e.g.:
from flask import Flask
import babel
app = Flask(__name__)
#app.template_filter()
def format_datetime(value, format='medium'):
if format == 'full':
format="EEEE, d. MMMM y 'at' HH:mm"
elif format == 'medium':
format="EE dd.MM.y HH:mm"
return babel.dates.format_datetime(value, format)
(This filter is based on babel for reasons regarding i18n, but you can use strftime too). The advantage of the filter is, that you can write
{{ car.date_of_manufacture|format_datetime }}
{{ car.date_of_manufacture|format_datetime('full') }}
which looks nicer and is more maintainable. Another common filter is also the "timedelta" filter, which evaluates to something like "written 8 minutes ago". You can use babel.dates.format_timedelta for that, and register it as filter similar to the datetime example given here.
Here's the filter that I ended up using for strftime in Jinja2 and Flask
#app.template_filter('strftime')
def _jinja2_filter_datetime(date, fmt=None):
date = dateutil.parser.parse(date)
native = date.replace(tzinfo=None)
format='%b %d, %Y'
return native.strftime(format)
And then you use the filter like so:
{{car.date_of_manufacture|strftime}}
I think you have to write your own filter for that. It's actually the example for custom filters in the documentation.
If you are dealing with a lower level time object (I often just use integers), and don't want to write a custom filter for whatever reason, an approach I use is to pass the strftime function into the template as a variable, where it can be called where you need it.
For example:
import time
context={
'now':int(time.time()),
'strftime':time.strftime } # Note there are no brackets () after strftime
# This means we are passing in a function,
# not the result of a function.
self.response.write(jinja2.render_template('sometemplate.html', **context))
Which can then be used within sometemplate.html:
<html>
<body>
<p>The time is {{ strftime('%H:%M%:%S',now) }}, and 5 seconds ago it was {{ strftime('%H:%M%:%S',now-5) }}.
</body>
</html>
You can use it like this in template without any filters
{{ car.date_of_manufacture.strftime('%Y-%m-%d') }}
Google App Engine users : If you're moving from Django to Jinja2, and looking to replace the date filter, note that the % formatting codes are different.
The strftime % codes are here: http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior
You can use it like this in jinja template
{{ row.session_start_date_time.strftime('%d-%m-%Y %H:%M:%S')}}
In this code the field name is row.session_start_date_time.
in flask, with babel, I like to do this :
#app.template_filter('dt')
def _jinja2_filter_datetime(date, fmt=None):
if fmt:
return date.strftime(fmt)
else:
return date.strftime(gettext('%%m/%%d/%%Y'))
used in the template with {{mydatetimeobject|dt}}
so no with babel you can specify your various format in messages.po like this for instance :
#: app/views.py:36
#, python-format
msgid "%%m/%%d/%%Y"
msgstr "%%d/%%m/%%Y"
I use this filter, it's in Spanish but you may change the names as you need.
#app.template_filter('datetime')
def date_format(value):
months = ('Enero','Febrero',"Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
month = months[value.month-1]
hora = str(value.hour).zfill(2)
minutos = str(value.minute).zfill(2)
return "{} de {} del {} a las {}:{}hs".format(value.day, month, value.year, hora, minutos)
There is a jinja2 extension you can use just need pip install (https://github.com/hackebrot/jinja2-time)
I use |length filter in my templates to display the recordcount of my objects, however I'm currently forced to use .count since it seems that using the filter against a related set doesn't work! The following
{{ myobject.retatedObject_set.all|length }}
prints literally:
{{ myobject.retatedObject_set.all|length }}
And this:
{{ myobject.retatedObject_set.all.count }}
returns the expected result...
BUT: count() generates an extra SQL query, which is why I always use |length filter which doesn't! (see my answer: https://stackoverflow.com/a/18578147/267719 to question django - show the length of a queryset in a view)
Can this be considered a bug in the Django template engine? How can I avoid the extra query?
EDIT:
After an hard debug I realized that the problem was the use of the django-debug-toolbar (which prints in its panels each filter used as normal strings) plus the use of AngularJS (which has the same syntax for its templates). I solved by reconfiguring AngularJS to use different symbols:
config(function($interpolateProvider) {
$interpolateProvider.startSymbol('{$');
$interpolateProvider.endSymbol('$}');
});
It has been 2day i am trying to figure out how to do that. I am a novice so please give as detailed explanation as possible.
I am doing this in my views.py
dict1 = simplejson.dumps(dict1)
return render_to_response('main_page.html', {
'js_testsuite':testsuite_dict,
'js_testset':js_testset,
'dict1':dict1})
In main_page.html
{% if js_testsuite %}
<select id="testsuites" name="testsuite" onchange="setOptions(document.selection.testsuite.selectedIndex);">
{% for key, value in js_testsuite.items %}
<option value={{ value }} name="testsuite">{{ key }}</option>
{% endfor %}
</select>
{% endif %}
In setoptions.js, which contains the function setOptions(value), to which i am passing selected index of the select box, and using this value i have to set the second select box and the data for this select box has to come from the views.py given above.
Also, I tried doing
var value_from_django = {{ dict1 }};
what are the other things im missing. Could you please provide a detailed explanation on this. I had been trying this for 2 days.
Is there a way in which I can pass the value from django views to the javascript directly bypassing the django template?
Can I pass the information from django views to the html template and then to the javascript?
The javascript I am referring to is a simple javascript not jquery.
Thanks for your support,
Vinay
You cannot pass values to javascript bypassing the template, unless you use an ajax call to start a separate request or unless you do something very unusual like embedding the data in a response header (don't actually do this, it is not what response headers are for!). The response, which includes the header and the body (the body being the part generated by the template) is the sum total of the information your application provides to your client, so unless you generate an additional request and fetch an additional response with ajax, you have no other options.
If you don't want to do that, then your options for passing information to the javascript via the template are basically the following:
Using an inline tag, create properly formatted javascript dynamically via the templating system. The example line you have, var value_from_django = {{ dict1 }}; is essentially what I'm talking about here, except that I'm not sure you can pass a dict through from django to javascript like that, because django's text output of a dict in the template is unlikely to be exactly the correct formatting for a javascript variable declaration. So, instead you can...
Translate your data into JSON and put that into your template, and then process that with the javascript. (This is usually done with an ajax call, but there's nothing stopping you from injecting the JSON data into the initial template directly.)
Or populate your HTML with the data you want and then use javascript to locate the HTML tag containing the data and parse the data out.
If you are trying to pass simple variables like integers, it might be easiest to do it with the first or third options. If you are trying to pass a more complex data structure like a dictionary, you will probably be better off using JSON (that's what it's for!)
I would like to give you more detailed and concrete instructions, but for that you will need to post more detail about what exactly is going wrong with your current approach and what your desired functionality is.
By the way: if it is at all feasible to include jquery on this page and use that instead of trying to use basic javascript, you should do so. It will make your life much, much easier.