Search code examples
pythondjangodjango-templatesabc

Using an abc.ABC class object in a Django template: why Django tries to instantiate it?


I want to use abc.ABC abstract class objects (not an instance) in a Django template. In these classes, I have several class methods (defined with the @classmethod decorator) that I'd like to use for displaying informations.

When I try to show the list object: {{ dataset.provided_services }}

I get a list of class objects displayed:

[<class 'dataset_services.table_service.QueryTableService'>, <class 'dataset_services.table_service.ExportTableService'>]

But if I try to iterate over this list:

<ul>
     {% for service in dataset.provided_services %}
     <li>
         <p>{{ service.name }}</p>
         <p>{{ service.description }}</p>
     </li>
     {% endfor %}
 </ul>

I get an error telling me that I cannot instantiate an abstract base class with abstract methods, as if django was trying to instantiate the class objects... Is this a normal behaviour? Is it possible to use class objects in a Django template without instantiating them?

PS: I'm using Django 1.8.5 and Python 3.4.


Solution

  • By default if the django template engine detects that a variable you are using is a callable it will call it before accessing sub-attributes. This is convenient in cases where you want the results of a function (which django doesn't allow you to explicitly call). If you'd rather not have a particular callable called in the django templates you can set the flag do_not_call_in_templates to True on your object. In your case you probably want to do this on your base class so every subclass has this attribute too.

    TL;DR: Set abc.ABC.do_not_call_in_templates = True

    Full documentation on how the django template language treats variables and for more info on the do_not_call_in_templates flag consult the django documentation.