Django view - load template from calling app's dir first

前端 未结 3 1341
甜味超标
甜味超标 2020-12-04 17:51

I try 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

相关标签:
3条回答
  • 2020-12-04 18:38

    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
    
    0 讨论(0)
  • 2020-12-04 18:42

    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))
    
    0 讨论(0)
  • 2020-12-04 18:47

    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.

    0 讨论(0)
提交回复
热议问题