Develop Odoo Views with Jinja Templating

Experimenting with a new way of templating instead of traditional qweb

Originally published at

Odoo has a built in templating engine called which is used for report templates and the frontend javascript framework. But as many Odoo developers know, there are different view types built into Odoo that do not use the qweb engine. This means that the qweb directives are not available on form views, tree views, kanban views, etc. (The most common types of views.)

This can drive us crazy when we need to figure out how to display or loop through some basic information in the common views.

I’ve found a good option/workaround to show static information in the views by utilizing the jinja2 package (which is already a requirement of Odoo). I'm going to walk you through the current way and my new way to handle it.

How can I show context in the view?

One of the common use cases that I’ve seen pop up for Odoo developers is being able to display some simple information like the context variable in the view. So let’s take a look at a sample view for a sale.order object where we might want to do that.

Views can’t live without their models

Odoo views are some shallow, old, rich men who only date models.

They are related directly to a data model in the system. This generally makes things much simpler when developing because there’s magic behind the scenes that automatically loads all of the data and renders the view. The major pitfall though is that when you aren’t operating within the expected use cases of the system, then you have to start introducing workarounds.

For example, if you were working outside of Odoo and you wanted to render a view then you directly inject data into that view. Using pesudo-code, that might look something like:

With the python code to load, render, and inject values looking like:

It’s a little bit of work, but very clear to us what’s happening. But Odoo automatically injects the model and fields into the view giving you access to that information but nothing else.

Fields for everything

Essentially any piece of information that you want to display on a view, which is not a static string written directly into the XML, must be in a field on the model.

Looking back at our context example we obviously must create a new field.

And this does work. It’s how we Odoo developers have operated, but it just feels wrong to be honest. When you start building out fairly complicated views then you continue to bloat your model more and more. Models in my mind are meant to represent some specific data structure that is stored in the system. It’s easy to wrap my head around the fact that the system needs orders, so we have an Order model. The fields on that model should only track the must-have data for an order.

But as more and more fields are added for view rendering, then it gets complicated keeping things straight. What do we actually need for order data in the business logic and what do we need to show on the order view? Should the order model really be responsible for storing or computing context?

It feels like there needs to be more separation there.

Another way with jinja2

jinja2 is an open source templating engine that is actually already a requirement of the Odoo source. It's used within the core.

I wanted to take advantage of it as a developer to pass some simple data into a view for rendering, which does not have anything directly to do with our model data structure. We are still bound to using the model class, but we can at least escape from using fields.

Here’s what that started to look like:

Now let’s break down what’s going on here.

1. Overriding fields_view_get

fields_view_get is the glue between the model and the view. It packages up all of the information that the view needs and returns a big dict. In that dictionary is a field called arch which is the xml from the view. That's what we need.

2. Generate a jinja2 environment

You can think of the jinja2.Environment class just like a configuration object. We just need to to set our open and end tags. I changed these to use triple brackets to avoid any conflict with core Odoo code. There are no occurences of triple brackets anywhere in the Odoo repository.

3. Load up our arch xml

Now we can create a template from the arch. jinja2 is a really simple to use package. You can take a string of html or xml and pass it into a template object.

4. Finally render is back out

Now we have a template object, created from the form xml. We just call the render function, inject whatever data we want, and put it back where it was before returning.

Bringing it together with the view

At this point, we can use the message data that we injected anywhere in our form view.

Pretty damn cool to see this work in a few lines of code. It lets us pass in any static data that we want.

Adding the context

Back to our original use case, let’s add the context. We need to update the data that we are injecting in and update the view. I’m just going to use the entire env object to show the flexibility you have.

Now we can reference the env variable anywhere within our views:

Refactor out a mixin

This is a cool option for developers, but it’s really not reusable in its current state. Am I going to override the fields_view_get on every model that needs this type of templating?

Of course not.

Let’s make a mixin for it:

The mixin lets us update our model and have a single hook for injecting data. You can see it’s following the same logic as shown above (condensed a bit for simplicity sake) and instead of directly passing a dict to our render method, we are using the view_data method which can be easily overwritten by models inheriting the mixin.

So this is what our order model can look like now:

Pretty simple, right? You can easily use it across any model now.

What about other directives?

jinja2 has a lot of features built into it. Above we are doing the simplest possible thing of rendering a variable, but of course you have full access to the features of the package. For example it's possible to iterate over objects:

Then we can utilize the for directive in the xml:

Go through the documentation and see what the possibilities are.


This might not be the perfect solution, but I really think it’s a viable one for developers who just need to display simple data. We do not have the option to use qweb directives in the most common types of views like form views and tree views. The work it would take to extend the core system to use qweb for those would not be worth it. It’s a big rewrite project.

But this is a nice little workaround. A single mixin that’s about 20 lines of code opens up a simple hook called view_data that injects whatever you want to render via jinja2.

I’m going to start playing around with this idea more and see about injecting other model data in, handling view updates, etc. and see where it takes me. Let me know if you try it out or have ideas about it. I’d love to hear them.

Best of luck coding on it.

Originally published at

Writes mostly #python code | Blogs at | Landlord | Takes pictures of food at | Freelancer