Django view - load template from calling app's dir first
I 开发者_如何学Pythontry to keep a somewhat consistent naming scheme on my HTML templates. I.e. index.html for main, delete.html for delete page and so forth. But the app_directories
loader always seems to load the template from the app that's first alphabetically.
Is there any way to always check for a match in the calling app's templates
directory first?
Relevant settings in my settings.py
:
PROJECT_PATH = os.path.realpath(os.path.dirname(__file__))
TEMPLATE_LOADERS = (
'django.template.loaders.app_directories.load_template_source',
'django.template.loaders.filesystem.load_template_source',
)
TEMPLATE_DIRS = (
os.path.join(PROJECT_PATH, 'templates'),
)
I've tried changing the order of TEMPLATE_LOADERS
, without success.
Edit as requested by Ashok:
Dir structure of each app:
templates/
index.html
add.html
delete.html
create.html
models.py
test.py
admin.py
views.py
In each app's views.py:
def index(request):
# code...
return render_to_response('index.html', locals())
def add(request):
# code...
return render_to_response('add.html', locals())
def delete(request):
# code...
return render_to_response('delete.html', locals())
def update(request):
# code...
return render_to_response('update.html', locals())
The reason for this is that the app_directories loader is essentially the same as adding each app's template folder to the TEMPLATE_DIRS setting, e.g. like
TEMPLATE_DIRS = (
os.path.join(PROJECT_PATH, 'app1', 'templates'),
os.path.join(PROJECT_PATH, 'app2', 'template'),
...
os.path.join(PROJECT_PATH, 'templates'),
)
The problem with this is that as you mentioned, the index.html will always be found in app1/templates/index.html instead of any other app. There is no easy solution to magically fix this behavior without modifying the app_directories loader and using introspection or passing along app information, which gets a bit complicated. An easier solution:
- Keep your settings.py as-is
- Add a subdirectory in each app's templates folder with the name of the app
- Use the templates in views like 'app1/index.html' or 'app2/index.html'
For a more concrete example:
project
app1
templates
app1
index.html
add.html
...
models.py
views.py
...
app2
...
Then in the views:
def index(request):
return render_to_response('app1/index.html', locals())
You could even write a wrapper to automate prepending the app name to all your views, and even that could be extended to use introspection, e.g.:
def render(template, data=None):
return render_to_response(__name__.split(".")[-2] + '/' + template, data)
def index(request):
return render('index.html', locals())
The _____name_____.split(".")[-2] assumes the file is within a package, so it will turn e.g. 'app1.views' into 'app1' to prepend to the template name. This also assumes a user will never rename your app without also renaming the folder in the templates directory, which may not be a safe assumption to make and in that case just hard-code the name of the folder in the templates directory.
I know this is an old thread, but I made something reusable, that allows for simpler namespacing. You could load the following as a Template Loader. It will find appname/index.html
in appname/templates/index.html
.
Gist available here: https://gist.github.com/871567
"""
Wrapper for loading templates from "templates" directories in INSTALLED_APPS
packages, prefixed by the appname for namespacing.
This loader finds `appname/templates/index.html` when looking for something
of the form `appname/index.html`.
"""
from django.template import TemplateDoesNotExist
from django.template.loaders.app_directories import app_template_dirs, Loader as BaseAppLoader
class Loader(BaseAppLoader):
'''
Modified AppDirecotry Template Loader that allows namespacing templates
with the name of their app, without requiring an extra subdirectory
in the form of `appname/templates/appname`.
'''
def load_template_source(self, template_name, template_dirs=None):
try:
app_name, template_path = template_name.split('/', 1)
except ValueError:
raise TemplateDoesNotExist(template_name)
if not template_dirs:
template_dirs = (d for d in app_template_dirs if
d.endswith('/%s/templates' % app_name))
return iter(super(Loader, self).load_template_source(template_path,
template_dirs))
The app_loader looks for templates within your applications in order that they are specified in your INSTALLED_APPS. (http://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types).
My suggestion is to preface the name of your template file with the app name to avoid these naming conflicts.
For example, the template dir for app1 would look like:
templates/
app1_index.html
app1_delete.html
app1_add.html
app1_create.html
精彩评论