@functools.lru_cache
def get_app_template_dirs(dirname):
"""
Return an iterable of paths of directories to load app templates from.
dirname is the name of the subdirectory containing templates inside installed applications.
[NOTE: Remember that "templates" was passed as argument, the dirname]
"""
template_dirs = [
Path(app_config.path) / dirname
for app_config in apps.get_app_configs()
if app_config.path and (Path(app_config.path) / dirname).is_dir()
]
# Immutable return value because it will be cached and shared by callers.
return tuple(template_dirs)
使用Path(app_config.path)/dirname可以得到appname/templates/。 对于每个安装的应用程序在这里找到for app_config in apps.get_app_configs(). 如果目录存在if app_config.path and (Path(app_config.path) / dirname).is_dir() template_dirs是已安装应用程序中具有模板文件夹的所有目录。
class MultipleObjectTemplateResponseMixin(TemplateResponseMixin):
"""Mixin for responding with a template and list of objects."""
template_name_suffix = "_list"
def get_template_names(self):
"""
Return a list of template names to be used for the request. Must return
a list. May not be called if render_to_response is overridden.
"""
try:
names = super().get_template_names()
except ImproperlyConfigured:
# If template_name isn't specified, it's not a problem --
# we just start with an empty list.
names = []
# If the list is a queryset, we'll invent a template name based on the
# app and model name. This name gets put at the end of the template
# name list so that user-supplied names override the automatically-
# generated ones.
if hasattr(self.object_list, "model"):
opts = self.object_list.model._meta
names.append(
"%s/%s%s.html"
% (opts.app_label, opts.model_name,
self.template_name_suffix)
)
elif not names:
raise ImproperlyConfigured(
"%(cls)s requires either a 'template_name' attribute "
"or a get_queryset() method that returns a QuerySet."
% {
"cls": self.__class__.__name__,
}
)
return names
2条答案
按热度按时间ozxc1zmp1#
首先,Django并不需要这种特定的文件夹结构来让模板工作,它只是一种既定的模式。当然,它有一个基本原理,正如官方文档所指出的那样:
模板命名空间
现在我们可以直接把模板放在polls/templates中了(而不是创建另一个polls子目录),但这实际上是一个坏主意。Django将选择它找到的第一个名称匹配的模板,如果您在不同的应用程序中有一个同名的模板,Django将无法区分它们。我们需要能够将Django指向正确的模板,最简单的方法是给它们命名,也就是说,把这些模板放在另一个以应用程序本身命名的目录中。
具体情况可以参考this question或that another。
简而言之,通过遵循此模式,您可以将模板组织成2组:
1.与您的特定站点或项目相关的模板可以位于
TEMPLATES['DIRS']
设置所指向的目录中;1.与特定应用程序相关的模板,如果您使应用程序可插入,则可以 * 按原样 * 提供,应该位于
'./appname/templates/appname/'
中(并且TEMPLATES['APP_DIRS']
必须为True)。这样可以避免此文件夹内的文件与外部文件之间的名称冲突。mefy6pfw2#
这是一个很长的答案。这个想法是真正解释Django在加载模板时是如何工作的。我甚至给你看了一些Django源代码来解释一些要点。
Django使用引擎来加载模板。这个答案适用于默认引擎
DjangoTemplates
(django.template.backends.django.DjangoTemplates
)让我们回顾一下您的评论:
“django模板文件夹需要创建一个以应用程序名称命名的子文件夹,然后包含模板文件。”
不,Django不要求你在templates文件夹中创建一个以应用名称命名的子文件夹。这不是要求,* 这只是一个建议。*
但为什么呢?让我们一步步来。
1)Django在哪里查找模板文件?
Django会在很多地方搜索模板目录,这取决于你的模板加载设置。
在
settings.py
文件中定义了两个位置。当配置TEMPLATES
时,您有DIRS
和APP_DIRS
。如下所示:DIRS
:是Django查找模板源文件的目录列表...
这应该设置为包含模板目录完整路径的字符串列表...
你的模板可以去任何你想去的地方,只要目录和模板是可读的web服务器...
示例:
所以Django没有必要的结构。你可以有你想要的目录,只要路径在这里列出并且可以被web服务器读取。一个常见的情况是当你想为所有应用程序都要使用的模板创建一个项目文件夹时:
'DIRS': [BASE_DIR/"templates"]
这告诉Django在位于基目录(根目录)的
templates
文件夹中查找文件。APP_DIRS
:告知引擎是否应在已安装的应用程序中查找模板…
当
APP_DIRS
是True
时,DjangoTemplates引擎会在已安装应用程序的templates子目录中查找模板。按照惯例,DjangoTemplates会在每个INSTALLED_APPS...
对于INSTALLED_APPS中的每个应用程序,加载器都会查找templates子目录。如果该目录存在,Django会在其中查找模板...
它是一个布尔值,
True
或False
。如果是True
,它将在每个应用程序中查找templates
子目录:**这是Django对你的唯一要求。**如果你想在每个应用中有模板,你必须在应用目录中有一个
templates
子文件夹。如果你有这些应用程序:
APP_DIRS: True
Django将在这里查找模板。2)为什么人们建议在templates文件夹(在已安装的应用程序中)中使用另一个具有应用程序名称的文件夹?
这是一个组织你的代码并帮助Django找到你真正请求的文件(模板命名空间)的问题。
重要的是要记住:当模板引擎加载模板时,它会按照
DIRS
设置中定义的顺序检查模板目录。如果在多个目录中找到同名模板,则使用找到的第一个目录。模板引擎检查
DIRS
目录后,将在APP_DIRS
目录中查找模板。如果在多个应用程序目录中找到同名模板,则使用INSTALLED_APPS中列出的第一个应用程序中的模板。让我们看看如果我们不做模板命名空间会发生什么。我们有以下文件夹:
如果我在
app_2
视图中工作,并希望加载模板detail.html
,我会有一个惊喜。而不是从app_2
加载模板,我会从app_1
加载模板。这是因为文件具有相同的名称,并且app_1
在INSTALLED_APPS
中排在第一位。为了避免这个问题,我们将应用程序的名称添加到模板文件夹中。
要从视图中加载模板,我需要“app_2/detail.html”。
3)您可以在Django源代码中检查这一点。
转到django/django/template/loaders/app_directories.py,你会发现:
它调用
get_app_template_dirs()
并将“template”作为参数传递。django/django/template/utils.py
使用
Path(app_config.path)/dirname
可以得到appname/templates/
。对于每个安装的应用程序在这里找到
for app_config in apps.get_app_configs()
.如果目录存在
if app_config.path and (Path(app_config.path) / dirname).is_dir()
template_dirs
是已安装应用程序中具有模板文件夹的所有目录。4)如果你正在使用基于类的视图(CBV),你可以得到一些功能。
您在
Blog
应用程序中有Post
型号的列表视图。在没有明确模板名称的情况下,Django会从对象(模型)的名称中推断出一个。在这个例子中:
其结构为:
应用程序名称:博客
model:other
视图类型:列表
正如你已经知道的,Django会在每个INSTALLED_APPS中查找“templates”子目录。
因此,如果
APP_DIRS: True
,则基于类的视图期望加载模板的完整路径为:这是CBV的预定义要求,但如果您定义了
template_name
参数,则可以对其进行修改。您可以在源代码中检查这一点:
转到django/django/views/generic/list.py
您已经:
其中:
opts.app_label:是应用程序的名称
型号名称:是模特的名字
self.template_name_suffix:是后缀,在本例中为“_list”
它们一起构成了CBV查找的默认模板名称:
文件。