Opened 11 years ago

Closed 11 years ago

#20412 closed New feature (wontfix)

Loader that searches templates in directory tree starting by its leave.

Reported by: anonymous Owned by: nobody
Component: Template system Version: 1.5
Severity: Normal Keywords: templates
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Summary

Suggestion to implement a dynamic template loader, where the origin of the template (where it is when it is searched for rendering), counts for where it is searched.

This solves the problem of template name collision, and allows for "overloading" of templates within apps.

Example of the problem

Consider the following example of app structure:

root/
     manage.py
     main/
          __init__.py
          settings.py
          urls.py
          views.py
          templates/
                    base.html
                    base/
                         header.html
                         secondary_header.html
          app1/
               __init__.py
               base_extension.html
               base/
                    secondary_header.html

with

    #base.html
    {% include "header.html" %}
    {% block secondary_header %}{% include "base/secondary_header.html" %}{% endblock %}
    
    #base_extension.html
    {% extends "base.html" %}
    {% block secondary_header %}{% include "base/secondary_header.html" %}{% endblock %}

My suggestion is to create a loader that:

if base.html is called (in main), it includes

main/base/secondary_header.html

if base_extension.html is called (in app1), it includes

main/app1/base/secondary_header.html

The current implementation always finds the secondary_header.html which appears first in the INSTALLED_APPS. So if the app1 is not prepared for being added at last in INSTALLED_APPS, there can be a name collision and the app1 (which would expect its own sec_header.html) has the sec_header.html from the main.

This occurs because all the current template loaders searches for the first occurrence of the template linearly in INSTALLED_APPS.

Suggestion

My suggestion is to have a loader that searches in the tree of the app calling the template with {%include%}: first searches in the templates of the app of the template (e.g. main/app1/templates/base). If none was found, it then searches in the level below (main/templates):

search "main/app1/templates"
if not found:

search "main/templates"
if not found:

raise TemplateNotFound

return template

this search can be recursive in the app tree, and this tree can easily be retrieved from the INSTALLED_APPS.

Simplifying in one sentence: the current approach searches linearly in INSTALLED_APPS. This approach searches recursively in the apps tree until either it reaches the root (template not found) or finding the template.

Discussion

There are (at least) two reasons in favor:

  1. this is what django uses in most situations, the directory tree. In the current implementation, template names can collide between apps and the order of INSTALLED_APPS is important for template loading. The current implementation "suggests" that each template has to have the name of the app for avoiding collision. In this loader there is no collision with other apps, the directory tree defines the apps dependencies.
  1. because it allows "overloading" of templates, as presented in the example I presented, where an app can now use the base.html (by extending it), but would still use its own secondary_header.

And (at least) two reasons against:

  1. the current implementation of loaders uses caching. I believe that in this implementation is more tricky, because the caching must be not only for a specific template name, but also from where it was called in the directory/apps tree.
  1. All the template related code (render, search, etc) only has one argument, the template name. This change leads to major problems in adjusting the code for this case.

Nevertheless, I believe the two reasons in favor are two important advantages in programing in django.

Change History (2)

comment:1 by Jorge C. Leitão, 11 years ago

comment:2 by Russell Keith-Magee, 11 years ago

Resolution: wontfix
Status: newclosed

I'm going to mark this wontfix.

Template loaders are used to defined changes in data source, not loading behaviour. Changing the loading behavior would be a pretty serious change to Django's behaviour, and I'm not convinced the benefits of the change you're proposing are sufficient to warrant introducing a change (especially given the caveat you give regarding caching).

If you feel strongly that we should introduce this change, feel free to open a discussion on Django-developers. Alternatively, this code could always exist as an external package.

Note: See TracTickets for help on using tickets.
Back to Top