Django template dir switching - django

Does anyone know a way to switch the TEMPLATE_DIR in django dynamically.
I need to create a set of templates for a mobile version and would like the templates to sit inside there own dir instead of inside the root template dir ie: I would like 2 template dirs 'templates' and 'mobile_templates' and not have to use 'templates/mobile' for the latter.
Do I have to write my own template loader?

You can set multiple template directories in your settings file and Django will search them in the order that you list them. Problem is that it doesn't care if you want template_x.html from directory a or b. If you have the same template_x in directory a and in b, it'll pull from which ever is listed first which can be confusing. A good way would be as follows:
Have only 1 template directory somewhere called 'templates'. Inside of this folder have a folder called 'mobile' and a template called 'default' (or whatever). Then when you call your template you just have to use the directory path as well.
In your view:
# some mobile view (everything omitted brevity)
get_template('mobile/some_template.html')
# some normal view (everything omitted brevity)
get_template('default/some_template.html')
In your templates:
Mobile Template:
{% extends 'mobile/base.html' %}
Normal Template:
{% extends 'default/base.html' %}
Settings File:
TEMPLATE_DIRS = (
'D:/some/path/to/templates',
)

Related

Django template extends wrong template

I have multiple apps in my project:
app1/
templates/
base.html
some_template.html
app2/
templates/
base.html
overview/
index.html
app2/templates/overview.index.html has this code:
{% extends 'base.html' %}
So it should extend app2/templates/base.html
But in fact it extends app1/templates/base.html! Why and how to fix it?
The app template loader returns the first template that matches, it doesn't know that you are rendering a template 'inside' a specific app.
The Django docs recommend that you put your app's templates in myapp/templates/myapp, not myapp/templates/. This prevents the templates from clashing.
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.
So in your case, you would change the structure to
app1/
templates/
app1/
base.html
some_template.html
app2/
templates/
app2/
base.html
overview/
index.html
You would then have to update the template name in your view, e.g.
return render(request, 'app2/some_template.html', {})
and in your template
{% extends 'app2/base.html' %}
Why? Because that's how discovering of django templates works.
Django will search for templates in each app's templates dir (in order that apps are presented in INSTALLED_APPS) and in global templates dirs. First found template will be served. This allows one app to use templates from other. It also allows to change templates for one app by another. Without that there wouldn't be easy way to style your admin panel by your own.
How to fix it? Create subdirectory in templates in each of your apps and keep here app-specific templates. Of course you will have to access them by entering path like:
{% extends 'app2/base.html' %}

JST through Django-Pipeline

I am creating a Backbone / Django application and I am wondering how to implement templates that reside in different files in for the Backbone views. From Rails I am used to using JST which allowed me to have a folder structure like
-js
-backbone
-templates
template1.jst
template2.jst
As far as I understand then it should be possible to the same using Django-Pipeline
but I find the implementation difficult.
I have added the following lines to my settings.py
STATICFILES_STORAGE = "pipeline.storage.PipelineStorage"
PIPELINE_CSS_COMPRESSOR = None
PIPELINE_JS_COMPRESSOR = None
PIPELINE_JS = {
'application': {
'source_filenames': (
'js/backbone/templates/**/*.jst',
)
}
}
and I added this to base.html
{% load compressed %}
{% compressed_js 'application' %}
I figured this would allow me to reference my templates through a JST object on the client, but it is not defined. Did I misunderstand the purpose of Django-Pipeline or am I simply missing something in the configuration?
No you did not misunderstand django-pipeline. You will be able to access the javascript templates in your backbone code. Before I give you the answer lets take a look at what the django-pipeline docs have to say.
Pipeline allows you to use javascript templates along with your javascript views. To use your javascript templates, just add them to your PIPELINE_JS group
So you can add your templates to the pipeline in the settings file like:
PIPELINE_JS = {
'templates': {
'source_filenames': (
'js/templates/**/*.jst',
),
'output_filename': 'js/templates.js'
}
}
Now you have to load these javascript templates in your browser.
Please Note: You have to make sure that you load the templates before your load any javascript code which uses the templates. Otherwise you will get an undefined error.
{% load compressed %}
{% compressed_js 'templates' %}
{% compressed_js 'other_backbone_files' %}
Now the docs say:
It will be available from your javascript code via window.JST
So you will have a global object named 'window' and you will be able to access the templates using its 'JST' property. The value of the JST property is another javascript object. The properties of this object are the names of your templates and its values are the templates. The names of your templates will depend on how you have included the templates in your settings file.
For example, if in your settings file you included the template as:
'source_filenames': (
'js/templates/**/*.jst',
)
and you had a template at 'js/templates/app/footer.jst', you can access the template in your javascript code in the following manner:
template: window.JST['app_footer']
Or if you did something like:
'source_filenames': (
'js/templates/app/*.jst',
)
OR
'source_filenames': (
'js/templates/app/footer.jst',
)
and you had a template at 'js/templates/app/footer.jst', you can access the template in your javascript code in the following manner:
template: window.JST['footer']
Notice that you need to include the name of the template from the first '*'
If you are still not sure then you can inspect the window.JST object in your javascript console to examine its properties.
If you want to use some other attribute name other than 'JST' then you can change it using the following setting in your settings.py
PIPELINE_TEMPLATE_NAMESPACE = 'window.Templates'
Now you can access your templates will be in the window.Templates objects instead of being in window.JST
Seems you should add also 'js/backbone/templates/.jst' as 'js/backbone/templates/*/*.jst' will match only templates in subfolder.

Django admin custom template tag

I try to customize my admin panel. I have copied change_list.html to the proper subfolder which is templates -> admin -> model -> change_list.html
While I customize the change_list.html I'd like to use a templatetag but I am not sure where should I put my custom template tag library.
When I put it under django/contrib/admin/templatetags/ it works fine but I want to keep it in my own project tree.
Do you have any idea ?
Note: I have also load my template tag in change_list.html as
{% load adminmedia admin_list i18n grp_tags myproject_tags %}
Thanks
Do not modify or add anything to directory containing Django (do not modify Django!). Keep everything in your project directory (like in the manual).
Admin templates are exactly the same as non-admin templates and you use custom template tags exactly the same way. Put your template tags in yourapp/templatetags/ directory. If your app is in the settings.INSTALLED_APPS that you can load it's tags by passing the module name to the load tag. It accepts also package.module syntax, so: {% load somelibrary %} or {% load package.otherlibrary %}

Difficulty overriding Django Admin template

I'm using Django 1.2.4 on Ubuntu 10.10. I'm trying to override the index.html template for the admin module. I've been following these instructions. I also looked at this question, but I'm still having difficulty.
The instructions say to create an admin directory in the templates directory:
templates/
admin/
index.html
I want to override a single block in the index.html. (Really, all I want to do is append some text to the end. Is there an easier way than copy/pasting the entire block and changing it?) (Update: Looks like {{block.super}} may help.)
To signal that I'm overriding, I put this at the top of my index.html:
{% extends "admin/index.html" %}
Of course, that results in a stack overflow (from the terminal):
Exception RuntimeError: 'maximum recursion depth exceeded in __subclasscheck__' in <type 'exceptions.RuntimeError'> ignored
What is the correct way to do this? I tried a symlink per an answer on the linked question, but that resulted in the following:
me#mycomp:~/foo$ sudo ln -s /usr/local/lib/python2.6/dist-packages/django/contrib/admin/templates/ django_admin
[sudo] password for me:
ln: creating symbolic link `django_admin': Protocol error
What am I doing wrong?
The recursion error is because you're extending the admin/index.html with itself.
You can either:
copy the entire admin/index.html template in your templates/admin/ directory, and it will replace the default template with yours
override the index.html per app or model, as explained here
I know this is late after the question, but you know, google traveling...
Amend settings.py with an extra template folder, for example:
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
"/home/mysite/webapps/django/myproject/templates",
"/home/mysite/webapps/django/lib/python2.7/django/", # extra folder
)
Then in myproject/templates/admin add your own index.html like:
{% extends "contrib/admin/templates/admin/index.html" %}
{% block branding %}
<h1 id="site-name">Administration for TheLittleButtonCo</h1>
{% endblock %}
Variations are possible, obviously. This works on Django 1.3.1 final
Not sure if you found the answer, but you need to change
{% extends "admin/index.html" %}
to
{% extends "admin/base_site.html" %}
as that is what the original index.html page overwrites. Because the Django system searches your templates folder before using the default admin one, so in this case it finds the admin/index.html in your templates, then it's trying to extend itself with the extend (hence the recursion error).
For reference you can customise the base_site.html in you templates too, it extends base.html. The best thing to do is copy the original from:
/usr/local/lib/python2.6/dist-packages/django/contrib/admin/templates/
and paste it into your templates folder as a starting point
I use an extra package, called django-smart-extends

Django - Admin - Mandatory fields with ' * '

At present, Django admin will show all the mandatory fields with a bold labels. Is it possible mark with * in the label instead of bold labels?
The Django admin uses templates to render the add/edit page for a model. It is possible to replace that template with one of your own (which extends from the original template) overriding the template blocks you need to in order to make the changes you want to.
Check out the Django docs regarding overriding admin templates for more information.
It's the admin/change_form.html template which you would need to alter in some way (since this template renders the page shown when you add a new instance or edit an existing one). The existing templates already apply a required class to the appropriate labels, so I would create a new template which looks like this:
{% extends "admin/change_form.html" %}
{% block extrastyle %}
{{ block.super }}
<style type="text/css">
/* add an asterisk using CSS */
.required:after {
content: " *";
}
</style>
{% endblock %}
Apply to a Single Model
You should use a model admin class if you want this template to be used for specific models, setting the change_form_template attribute, as described in this section of the docs to the location of the template file you have created.
Apply to a Single App
If you want template to apply to models in an entire app create a templates folder inside the root of the app. Django will automatically look for templates there, so if you create a folder called admin and place a file in there called change_form.html it will automatically override the default Django template of that name (admin/change_form.html).
Project Wide
In order to apply this template project wide create a folder somewhere (not inside an app) called templates. Again place your new template in this directory at admin/change_form.html.
Next edit the template directories Django setting specifying the location of this directory in order to allow Django to find the template and override the default templates in the same way as before only project wide and not just app wide.
This is quite a complex set of things to do, especially for such a simple change and you may find it tricky if you have not worked with admin templates before (or even if you have).
Hopefully you now understand what is required to change an admin template, its actually fairly elagant (as is Django) but in my opinion not worth the effort just to change to some asterisks.