In the first and second parts of this three-part tutorial series, we saw how to lay out the template structure in a Flask-based application using Jinja2 in a modular manner and how to create custom context processors, filters and macros in Jinja2.
In this part, we will cover how to implement advanced date and time formatting at template level in Jinja2 using moment.js.
Getting Started
Date and time formatting is a painful thing to handle in web applications. Handling them at the level of Python, using the datetime library, increases the overhead and is pretty complex when it comes to handling time zones correctly. We should standardize the timestamps to UTC when stored in the database, but then the timestamps need to be processed every time they need to be presented to the users worldwide.
It is a smart thing to defer this processing to the client side, that is, the browser. The browser always knows the current time zone of the user and will be able to do the date and time manipulation correctly. Also, this takes off the necessary overhead from our application servers.
Just like any JS library, Moment.js can be included in our app in the following manner. We will just have to place the JS file, moment.min.js
, in the static/js
folder. This can then be used in our HTML file by adding the following statement along with other JS libraries:
<script src="/static/js/moment.min.js"></script>
The basic usage of Moment.js is shown in the following code. This can be done in the browser console for JavaScript:
>>> moment().calendar(); "Today at 9:37 PM" >>> moment().endOf('day').fromNow(); "in 2 hours" >>> moment().format('LLLL'); "Wednesday, January 27, 2016 9:38 PM"
To use Moment.js in our application, the best way will be to write a wrapper in Python and use it via jinja2
environment variables. Refer to this runnable for more background. Add a file named momentjs.py
at the same level as my_app.py
.
flask_app/momentjs.py
from jinja2 import Markup class momentjs(object): def __init__(self, timestamp): self.timestamp = timestamp # Wrapper to call moment.js method def render(self, format): return Markup("<script>\ndocument.write(moment(\"%s\").%s);\n</script>" % (self.timestamp.strftime("%Y-%m-%dT%H:%M:%S"), format)) # Format time def format(self, fmt): return self.render("format(\"%s\")" % fmt) def calendar(self): return self.render("calendar()") def fromNow(self): return self.render("fromNow()")
Add the following line in flask_app/my_app.py
after app
initialisation. This will add the momentjs
class to jinja
environment variables.
# Set jinja template global app.jinja_env.globals['momentjs'] = momentjs
Now moment.js can be used to format date and time in templates as follows:
<p>Current time: {{ momentjs(timestamp).calendar() }}</p> <br/> <p>Time: {{momentjs(timestamp).format('YYYY-MM-DD HH:mm:ss')}}</p> <br/> <p>From now: {{momentjs(timestamp).fromNow()}}</p>
Conclusion
In this tutorial series, we covered the basics of Jinja2 templating from the perspective of Flask. We started with very basics of Jinja2 and learnt the best practices on how to lay out the template structure and leverage inheritance patterns.
Then we created some custom context processors, filters and macros which come very handy in advanced templating. The final tutorial covered how moment.js can be utilised along with Jinja2 to create highly flexible and powerful datetime formatting.
Comments