Django “TemplateDoesNotExist ” Error but “Using loader django.template.loaders.app_directories.Loader” File Exists

前端 未结 7 1861
我在风中等你
我在风中等你 2021-01-05 19:05

Template Loader finds the template but template is not loaded

TemplateDoesNotExist at /cardpayment/

cardpayment.html

Request Method:     G         


        
7条回答
  •  星月不相逢
    2021-01-05 19:36

    I'm also using the DIRS config option in a similar way to you and I've just run into the same problem in Django 1.8.2. The issue seems to relate to the way you invoke django.shortcuts.render (or django.shortcuts.render_to_response) in your views - are you using these?

    TL;DR - try changing your invocation of render_to_response in your views so that you don't pass a context_instance or any deprecated argument, such as the previously often used django.template.RequestContext. If you do pass a context_instance, or any deprecated argument, the django template loading code uses a legacy path that doesn't support the DIRS option and your template will not be loaded - even if it exists on disk.

    Here's a section of relevant code from the Django source (django/shortcuts.py) that shows how this situation comes about:

    def render_to_response(template_name, context=None,
                           context_instance=_context_instance_undefined,
                           content_type=None, status=None, dirs=_dirs_undefined,
                           dictionary=_dictionary_undefined, using=None):
        """
        Returns a HttpResponse whose content is filled with the result of calling
        django.template.loader.render_to_string() with the passed arguments.
        """
        if (context_instance is _context_instance_undefined
                and dirs is _dirs_undefined
                and dictionary is _dictionary_undefined):
            # No deprecated arguments were passed - use the new code path
            content = loader.render_to_string(template_name, context, using=using)
    
        else:
            # Some deprecated arguments were passed - use the legacy code path
            content = loader.render_to_string(
                template_name, context, context_instance, dirs, dictionary,
                using=using)
    
        return HttpResponse(content, content_type, status)
    

    If you follow this through to the loader's render_to_string method (in django/template/loader.py) you can see your template won't be loaded if you pass any deprecated arguments to render_to_reponse in your views:

    def render_to_string(template_name, context=None,
                         context_instance=_context_instance_undefined,
                         dirs=_dirs_undefined,
                         dictionary=_dictionary_undefined,
                         request=None, using=None):
        """
        Loads a template and renders it with a context. Returns a string.
    
        template_name may be a string or a list of strings.
        """
        if (context_instance is _context_instance_undefined
                and dirs is _dirs_undefined
                and dictionary is _dictionary_undefined):
            # No deprecated arguments were passed - use the new code path
            if isinstance(template_name, (list, tuple)):
                template = select_template(template_name, using=using)
            else:
                template = get_template(template_name, using=using)
            return template.render(context, request)
    
        else:
            # Some deprecated arguments were passed - use the legacy code path
            for engine in _engine_list(using):
                try:
                    # This is required for deprecating properly arguments specific
                    # to Django templates. Remove Engine.render_to_string() at the
                    # same time as this code path in Django 2.0.
                    if isinstance(engine, DjangoTemplates):
                        if request is not None:
                            raise ValueError(
                                "render_to_string doesn't support the request argument "
                                "when some deprecated arguments are passed.")
                            continue
                        # Hack -- use the internal Engine instance of DjangoTemplates.
                        return engine.engine.render_to_string(
                            template_name, context, context_instance, dirs, dictionary)
                    elif context_instance is not _context_instance_undefined:
                        warnings.warn(
                            "Skipping template backend %s because its render_to_string "
                            "method doesn't support the context_instance argument." %
                            engine.name, stacklevel=2)
                    elif dirs is not _dirs_undefined:
                        warnings.warn(
                            "Skipping template backend %s because its render_to_string "
                            "method doesn't support the dirs argument." % engine.name,
                            stacklevel=2)
                    elif dictionary is not _dictionary_undefined:
                        warnings.warn(
                            "Skipping template backend %s because its render_to_string "
                            "method doesn't support the dictionary argument." %
                            engine.name, stacklevel=2)
                except TemplateDoesNotExist:
                    continue
    
            if template_name:
                if isinstance(template_name, (list, tuple)):
                    template_name = ', '.join(template_name)
                raise TemplateDoesNotExist(template_name)
            else:
                raise TemplateDoesNotExist("No template names provided")
    

提交回复
热议问题