Django template outliner - django

I'm trying to obtain a visual representation of the templates of a Django project, as a hierarchy.
The main idea is to get a list of template names as the default template loading machinery would return (ie honoring TEMPLATE_DIRS, TEMPLATE_LOADERS, etc.) and then parsing the templates looking for {% block %} and {% extends %} tags, in order to create a tree structure. Finally use grapviz for the visualization.
I'm not sure if it's a viable approach. But just to start, how can I load the templates the way I described?
Or maybe, does something similar already exist?

Normally, templates are looked up by names online, there is no root entry for every template that might be used.
Thus if you want to grep all used templates in a project, you need to scan every place that loaders in TEMPLATE_LOADERS might check, to generate possible entries for later bottom-to-up checking. This would be hard, some backends of loaders might even does not allow fetch-by-directory operation.
Or you could parse views and urls files inside INSTALLED_APPS to grep template names, but this only works w/ hard-coded name of template and even more difficult.
Also, there might be templates loaded from hard-coded string...
For a given template name, its easier to load the template and check nodes inside it, just as your idea. You could check django.template.base to know how it works.
Furthermore, you could take advantage of django-debug-toolbar to show the templates used for a request. And, IMO, keeping template structure flat, simple and thus determined, is easier to achieve.

Related

Rendering from strings instead of files with MarkoJS

I'm using markojs for my emails templates but now we are moving these templates inside our database to edit them online.
We still need to use marko to keep our full HTML structure and variables behavior aswell.
I've found 2 ways to get templates as string like renderSync() method but it need the template to exist as file before or with compile() but I don't know how to make it work with variables handling.
You can use Marko's load method to compile templates and get back the template instance which you can then render to get the final HTML:
const template = require("marko").load(templatePath, templateSource, compilerOptions);
const html = template.renderSync(data);
You probably don't need to pass any custom compilerOptions and can omit the last argument.
Even though your template doesn't exist on disk, you still need to pass a templatePath to a real directory with a dummy .marko file. For instance you could do this:
const templatePath = path.join(__dirname, `${database.id}.marko`);
The templatePath is used for two purposes:
As a key for node's require cache. If you request to compile the same filename multiple times, you will get the original compilation. This might mean you need to purge the require cache when a template is edited: delete require.cache[templatePath];
To discover custom Marko tags. If you have custom tags/components that are intended to be used by the email templates, you should make sure that the path specified by templatePath allows those tags to be discovered.

Why do we to put templates in <app>/templates/<app>/blah.html, even though the default path is <app>/templtes/

According to the latest Django Documentation for templates namaspace, we should put our templates in the order.
app/templates/app/template_files
But the default location it looks for templates is app/templates/, why not simply create a template file in templates sub-folder ?
Template namespacing
Now we might be able to get away with putting our templates directly in polls/templates (rather than creating another polls subdirectory), but it would actually be a bad idea. Django will choose the first template it finds whose name matches, and if you had a template with the same name in a different application, Django would be unable to distinguish between them. We need to be able to point Django at the right one, and the easiest way to ensure this is by namespacing them. That is, by putting those templates inside another directory named for the application itself.
According to the explanation give in the documentation my approach would lead to ambiguity. so let's say we have two apps viz.
app1 & app2 and they have index.html in app/templates/ path, why can't django distinguish between two different path - /app1/templates/index.html & /app2/templates/index.html ?

Does Django cache custom tags and filters?

I have a considerable number of custom template tags that perform a variety of functions, including:
simple string transformation
display of complex ui elements
timestamp manipulation and formatting
handling and display of user avatars
etc...
All of these functions reside in a single file: app/templatetags/custom_tags.py. When I want to use one of these tags in a template, I import all of them using {% load custom_tags %}.
However, only a small subset of the available tags are actually used in any given template. In other words, all these functions are being 'loaded' into the template, yet only a few of them are called in a specific web request.
Is this inefficient, in terms of performance? Should I be loading code more conservatively -- i.e., splitting up my custom tags into separate files and only loading the subset that I need?
Or does this not matter, because all tags are loaded in memory -- i.e., subsequent calls to {% load custom_tags %} elsewhere in the application won't result in any additional overhead?
I apologize if there are incorrect assumptions or premises in this question. I'd love to have a better understanding of the implications of importing python code in general, or in a Django environment specifically.
For Django <= 1.8:
The load tag is defined here and actually does the loading here and here. Both places call to get_library, defined here. According to the docstrings there, yes, it caches template tag/filter libraries within the same process in the dictionary initalized here.
For Django 1.9:
The modules for template tags are now being loaded even earlier, when the parser is instantiated, and the libraries are being stored directly on the parser. Load tags call out to find_library here and here, which just gets the already-loaded tag directly from the parser.
Aside from the actual loading activity
As #spectras points out below, regardless of the Django version, the tag's loading behavior is, strictly speaking, a side effect, and the tag returns (<=1.8/1.9) a no-op node(<=1.8/1.9), which renders no content--so there's not really a performance consideration as far as that goes.

Why are we advised to put templates in project/app_name/templates/app_name/?

In the django tutorial, it recommends that an application's templates go in
project/app_name/templates/app_name
which results in them being referred to from views something like this:
class ScenarioDetails(generic.DetailView):
model = Scenario
template_name= "cmmods/scenario.html"
I would like to understand what is behind this recommendation.
I can't see what situation would make it bad to put templates in
project/app_name/templates
and refer to them thusly:
class ScenarioDetails(generic.DetailView):
model = Scenario
template_name= "scenario.html"
What is behind this recommendation?
It avoids name clashes and it explicitly refers to the app where the template is located.
Say your app defines a couple of templates that are very similar. An easy way to achieve this is to use a base template, e.g. 'base.html'. This is quite a common name, and it is quite likely that other apps use the same name. If you put this template in your root template folder, the names clash and both apps get the same template, depending on which one comes first (or last) in your INSTALLED_APPS.
By putting each template in a folder named after your app, you avoid these name clashes. It is also easier to locate the template from just the template name, which is very useful if your app uses templates from other apps.
Say you use the template detail.html in your app2 app. Django will look for this template in all template folders in the order they are found. Now, your installed apps looks like this:
INSTALLED_APPS = (
'app1',
'app2',
)
Django will look for the detail.html file in the following locations, and picks the first one it finds:
/path/to/project/app1/templates/detail.html
/path/to/project/app2/templates/detail.html
Even though app2 expects the template file in app2/templates/, Django will give the template in app1/templates/ if it exists. You get the wrong template because the (relative) names are the same.
Now, if you would put your template in app2/templates/app2/detail.html, you are sure you get the right template.
The reason is that templates need to be kept separate from templates of other Django apps to prevent collision. This is why all templates in Django apps should be saved in a directory called app_name/templates/app_name.
For example, without doing this, two apps with the same template (same filename) would have a problem if they're used together in the same Django project (without additional work, Django wouldn't know which of these home.html files to use):
app1/templates/home.html
app2/templates/home.html
As a result of the convention to include the app name in the templates path, you can safely create and release a Django app and reuse it in other Django projects without fearing that there will be a filename problem.

How to tell Template where to load files from?

I want to store some templates in the database for custom rendering. I create a Template object with the string coming from the database and then I use the render method. So far so good.
Now I would like to be able to use the extension mechanism to load a template from another one with the {% extends %} tag so that even the base template could be loaded from the database. I realized that the extension mechanism works and uses the global configuration given in settings. So I'm able to extend from a file from my template loaders. I can also add my custom loader to look for data source in the database. However I would like my TemplateLoader to know what database object was the source of the first template, and look for base files depending on that.
I would expect a hook into the Template object to specify custom TemplateLoaders instead of global ones. I've looked into documentation and source files, but failed to find such an hook.
Any hint?
** CLARIFICATION **
Since I dind' get an answer, I try to clarify the question. Suppose I have a template to render some kind of objects of my database. This template uses an {% extends "base.html" %} to load the skeleton file with the base layout of the site. Suppose now that for some of these objects (based for example on an attribute in the object) I want to modify the base file (not the template!). How do I achieve this?
You can easily add feature to load you templates from databases with: http://django-dbtemplates.readthedocs.org/en/latest/.