On Dec 10, 6:58 pm, "Joseph Kocherhans" <[EMAIL PROTECTED]> wrote:
> On 12/9/07, Gary Wilson <[EMAIL PROTECTED]> wrote:
>
>
>
>
>
> > Vinay Sajip wrote:
> > > On Dec 7, 6:35 pm, "Marty Alchin" <[EMAIL PROTECTED]> wrote:
> > >> On Dec 7, 2007 12:56 PM, Vinay Sajip <[EMAIL PROTECTED]> wrote:
>
> > >>> this be allowed/disallowed/checked for? As for standard template
> > >>> loading, there's no reason that the standard template loading
> > >>> (app_loader) code could not be modified to work with App instances,
> > >>> using whatever logic to use the application path and/or label to
> > >>> locate the templates. Or have I misunderstood Malcolm's comment?
> > >> The problem here is that a distributed app has to expect specific
> > >> paths to its templates, both for its views (for render_to_response,
> > >> for instance) and its templates (for extends and include). If my
> > >> template says "{% extend 'modular/module.html %}', what would happen
> > >> if someone had "App('modular', name='mod_app')"? How would the extends
> > >> tag be able to locate the correct template if someone essentially
> > >> renamed the app?
>
> > > The current code in django/template/loaders/app_directories.py appears
> > > to search in the directory 'templates' relative to the directory
> > > containing the app module. I can't quite see why this needs to change:
> > > it's independent of the app label, shouldn't that be OK?
>
> > It does look in the "templates" directory of the application directory;
> > however, it gets treated as a standard, global template directory.  Current
> > practice is to repeat the name of your application inside the "templates"
> > directory to avoid name collisions.  For example:
>
> > myblogapp/templates/myblogapp/base.html
>
> > So even if you were to specify an app_label of "blog" for this app, you 
> > would
> > still have to reference the templates as "myblogapp/base.html".
>
> > The current app_directories template loader has always bugged me because it 
> > is:
>
> > 1) inefficient - all application template directories are added as global
> > template directories and are searched each time by the template loader.
>
> > 2) unpredictable - any application could, unbeknownst to the developer,
> > override another application's templates.  For example, an application could
> > include an "admin" directory in its "templates" directory that overrides 
> > admin
> > templates.
>
> > 3) not DRY - just silly I have to make my "templates" directory one level
> > deeper with a duplicated name.
>
> > For those of you that have stopped using the app_directories loader in favor
> > of the standard filesystem loader and TEMPLATE_DIRS, what was your reasoning
> > behind doing so?
>
> > And doesn't doing things this was cause the same problems?  Every directory
> > added is going to get searched as a global template directory.  You're still
> > going to have the unpredictability of apps possibly overriding templates of
> > other apps.  You are still going to be repeating yourself by having to put 
> > the
> > app in INSTALLED_APPS and its template directory in TEMPLATE_DIRS.
>
> > I have always thought that you should be able to put an app's templates in 
> > its
> > "templates" directory and that those templates should only be accessible 
> > when
> > using the app name in front of it, like "myblogapp/base.html".  The
> > "myblogapp/templates" directory should not be looked at in any other case, 
> > and
> > only global template directories are looked at every time by the filesystem
> > template loader.
>
> > This should also work with custom app_naming, since now the templates would 
> > be
> > accessible with the custom name, i.e. "blog/base.html".  This would also 
> > work
> > if you had two instances of an app running under two different names, i.e.
> > "blog1/base.html" and "blog2/base.html".  And I could still override these 
> > in
> > a global template directory with directories named "blog1" and "blog2".
>
> FWIW I pretty much agree with Gary. And surprisingly, I actually agree
> with myself of two years ago when we discussed this before [1] [2].
> There's also another related thread [3] and a ticket [4] that Adrian
> and Jacob both agreed to mark as wontfix. Their arguments against such
> a template loader are in the ticket. They have a valid point, but
> changing the app_directories template loader still seems like the
> cleanest way to deal with custom app_labels and templates to me. Maybe
> this will prompt ideas for another solution though.
>
> Joseph
>
> [1]http://groups.google.com/group/django-developers/browse_thread/thread...
> [2]http://groups.google.com/group/django-developers/msg/f10d34ebd266fbe2
> [3]http://groups.google.com/group/django-developers/browse_thread/thread...
> [4]http://code.djangoproject.com/ticket/1586

Joseph, thanks for the summary - very useful. I pretty much agree with
what I think you/Gary are saying. If my understanding is correct,
there are two main approaches to template loading (provided as
batteries-included template loaders):

1. Search through the directories in settings.TEMPLATE_DIRS. This
approach suffers from the need to list app template directories in
TEMPLATE_DIRS, which is not DRY because it (sort of) repeats the list
of installed apps in INSTALLED_APPS. You also have to use absolute
paths rather than relative paths, which is an added pain. Efficiency
is not optimal because of the linear search through the directory
list.
2. Search through 'templates' subdirectories in each of the installed
apps. This is good because you don't have to add a repeated directory
list in TEMPLATE_DIRS, but again not optimal because of the linear
search: if every app in INSTALLED_APPS defines some templates, then
templates for apps positioned later in INSTALLED_APPS pay a run-time
penalty because the 'templates' directories of all earlier apps are
searched first.

Both approaches suffer from the fact that multiple apps can define the
same template names - e.g. "base.html" as an ancestor template. The
official way to disambiguate is to place the templates one level down,
using a prefix folder reflecting the app. So in app1 you need to
inherit "app1/base.html" from "app1/child.html" and in app2 you need
to inherit "app2/base.html" from "app2/child.html". This is somewhat
kludgy, to say the least.

It seems like what is needed is an app-centric strategy for template
loading. I'll propose an alternative solution in the interests of
stimulating further discussion, but please be gentle with me ;-)

Assuming for the purposes of discussion that get_template is renamed
to old_get_template, which uses the current strategy, then pseudo code
for the proposed approach might look something like:

def get_template(template_name):
        calling_app = get_calling_app() # figure out later how this will work
        if calling_app is None:
                result = old_get_template(template_name)
        else:
                try:
                        result = app_specific_loader(calling_app, template_name)
                except TemplateDoesNotExist:
                        result = old_get_template(template_name)
        return result

We assume that calling_app is any app-related object from which we can
get the location of the 'templates' subdirectory, and that
app_specific_loader will get this directory and look for the template
in it, avoiding the kludgy prefix: template names would be mapped
directly below the 'templates' directory in the application. So, for
some app with path 'my.package.app', 'base.html' would map to '/path/
to/my/package/app/templates/base.html', 'news/child.html' would map to
'/path/to/my/package/app/templates/news/child.html', etc. For the
purposes of loading its own templates, an app never needs to refer to
its app_label and doesn't care about it at all. And since the app is
searched first, it can easily override templates defined in other
apps, e.g. admin templates, by returning its own versions.

How would an inter-app template reference work? One possible way would
be to see if a template name looked like '~some_label/some/path/
base.html', in which case the '~some_label' part would be stripped off
and used to locate the app with label 'some_label', and the template
would be expected to be in '/path/to/app/whose/label/is/some_label/
templates/some/path/base.html'. But there's still a problem with
needing to fixup template references if an app gets renamed in
settings.INSTALLED_APPS, and there's no easy way to avoid this
(AFAICT) unless the whole app path is used to specify the app, rather
than a label. For example, '~django.contrib.admin/auth/
base_site.html'.

How might get_calling_app() work? To avoid large scale changes in
function/method signatures, and backward compatibility headaches, a
threadlocal seems the easiest way of achieving this. Every request
which maps to an app will trigger calling a view, which in turn will
load templates as part of its operation. So, if each view is
associated with an app, then the resolver machinery can set the
threadlocal appropriately during request dispatch, and get_calling_app
can read it. The app for each view could be specified either in the
tuples passed to django.conf.urls.defaults.patterns, or as an optional
keyword argument to it, which would be treated as applying to all
tuples passed in that call. I haven't of course thought all of this
through fully, but I want to make sure I'm not going off down a road
which the core developers are uncomfortable with. Plus, I've probably
missed some obvious point which kills the idea stone dead :-(

Does any of this make sense?

Regards,

Vinay Sajip

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-developers@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to