The reason for this suggestion is over the years, while writing templates, I've had to spend a lot of time trying to figure out why I was getting an unexpected value (often an empty string) substituted for a template variable when that variable clearly had a different value.
The reason that happens, of course, is that the ​django.template.base.Variable._resolve_lookup <https://github.com/django/django/blob/21ff23bfeb4014bceaa3df27677fb68409c0634d/django/template/base.py#L851> method tries to invoke every callable value in a variable's resolution path, including the variable itself. If that callable is a function with parameters, for example, the invocation raises an exception and you end up with an empty string (or whatever value you use for the string_if_invalid setting) as a result. If it's a different kind of callable, like a class or a regular object that implements __call__ <https://code.djangoproject.com/ticket/15791> for whatever reason, you just end up with something other than what you wanted. While automatically invoking callables makes sense when the current "bit" in the resolution path is a method and the previous "bit" was an instance, it is very surprising when the "callable" value is not actually a method (e.g. it's a class or a standalone function), in which case I don't think it makes sense to call it automatically. In fact, this goes against the fundamental Python (and Django) philosophy of *"Explicit is better than implicit".* There are legitimate cases where you might want to pass something like a class object to a template and to not have it mysteriously replaced by an arbitrary instance of that class (see #30197 <https://code.djangoproject.com/ticket/30197>). I also think that the existing workaround of setting a do_not_call_in_templates <https://code.djangoproject.com/ticket/15791> attribute on such object is insufficient to cover all such cases (e.g. when the object is a class or function that comes from some library and you don't want to risk messing with it). My comment on #30197 <https://code.djangoproject.com/ticket/30197#comment:5> suggested replacing this implicit behavior with an explicit tag like {% call foo %} instead of {{ foo }} (this example assumes that foo is callable). Although that would be a breaking change, I think it might be worth considering because it would be in the spirit of upholding the *"Explicit is better than implicit"* principle, and prevent a frequently-occurring problem for template authors (which is evidenced by the prevalence of tickets and StackOverflow questions about this topic; e.g. https://stackoverflow.com/questions/6861601/cannot-resolve-callable-context-variable ) However, in #30205 <https://code.djangoproject.com/ticket/30205>, I am proposing a *non-breaking *change to solve this problem -- a new template tag similar to autoescap <https://django.readthedocs.io/en/stable/ref/templates/builtins.html#autoescape> e <https://django.readthedocs.io/en/stable/ref/templates/builtins.html#autoescape>, which could be used like this: {% callables off %} <div>The class name is {{ foo.bar|type_name }}</div>{% endcallables %} (in the above example foo is an object containing an attribute named "bar" whose value is a class, and |type_name is a user-defined filter that returns the "__name__" attribute of its argument) -- You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at https://groups.google.com/group/django-developers. To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/962bead6-e186-416b-a18a-3e0f2ad23da9%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.
