如果评估的变量为 False,为啥我的 django 模板中的这个 IF 语句会执行?

Posted

技术标签:

【中文标题】如果评估的变量为 False,为啥我的 django 模板中的这个 IF 语句会执行?【英文标题】:Why does this IF statement in my django template execute if the evaluated variable is False?如果评估的变量为 False,为什么我的 django 模板中的这个 IF 语句会执行? 【发布时间】:2012-08-18 09:58:54 【问题描述】:

我正在开发一个不属于我的 django 项目,但正在尝试将本地 css/js 选项添加到 webapp。

在 settings_local.py 我添加了这个:

if os.path.exists('templates_local/local.css'):
    LOCAL_CSS = True
    logging.debug('LOCAL_CSS: %s' % LOCAL_CSS)
else:
    LOCAL_CSS = False
if os.path.exists('templates_local/local.js'):
    LOCAL_JS = True
    logging.debug('LOCAL_JS: %s' % LOCAL_JS)
else:
    LOCAL_JS = False

这似乎有效(见下文)。在我的主模板中我添加了

% if LOCAL_CSS %
    % compress css  %
        % include "../templates_local/local.css" %
    % endcompress  %
% endif %

(该项目使用 django-compressor)。

如果存在 local.css 文件,这将按预期工作,但如果文件不存在,我会收到错误:

渲染时捕获 TemplateDoesNotExist:../templates_local/local.css

在堆栈跟踪中,LOCAL_CSS 被列为 False。不幸的是,堆栈跟踪下降以显示 IF 没有找到文件(这是预期的),但似乎不包括 IF 的评估方式,尽管它正在执行,就好像它正在评估为 True ......但无论如何,这并不能帮助我找出问题所在。

我还尝试明确检查if LOCAL_CSS == True,以防上面的 if 语句仅仅因为变量存在而评估为 True。

无论如何,我希望这是迄今为止我错过的关于 django 的一个奇怪的细节,或者有更多经验的人会立即看到我做错了什么。

如果您认为我以错误的方式处理此问题,请随时仔细阅读我最初没有接受者的问题:https://***.com/questions/11975054/django-recipe-for-local-css-and-local-js-like-settings-local-py-for-app-with-m


回答! - 三个独立的问题

通常情况下,多个错误步骤似乎是一个更简单的单个问题

最终的工作实际上非常简单:

在supervacuo's suggestions,经过一番争论,我添加了一个上下文处理器,templates_local/context.py:

import os.path

install_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), '..'))
localcss = os.path.join(install_dir, 'templates_local', 'local.css')
localjs =  os.path.join(install_dir, 'templates_local', 'local.js')

def local_static(context):
    return 
        'LOCAL_CSS': localcss if os.path.exists(localcss) else False,
        'LOCAL_JS':  localjs  if os.path.exists(localjs)  else False,
        

并将 "rooibos.templates_local.context.local_static", 添加到 settings.py 文件中预先存在的 TEMPLATE_CONTEXT_PROCESSORS 列表中。

我只需要将模板中的 if 语句切换为 if not:

% if LOCAL_CSS != False %
    % compress css  %
        % include LOCAL_CSS %
    % endcompress  %
% endif %

出了什么问题?

问题 1 - 我对模板上下文中可用的内容感到困惑

见supervacuo's 1st suggestion

问题 2 - 缺乏经验/熟悉环境

我没有发现/怀疑在 django 的上下文中,像 os.path.exists() 这样的方法是从 manage.py 的位置执行的,而不是你调用它的 path/file.py(哪个事后看来是有道理的)

问题 3 - 有缺陷的逻辑,太简单的方法,也许是别的

我怀疑如果TEMPLATE_DEBUG = True 文件不存在,您可能无法包含带有路径字符串(例如% include "../templates_local/local.css" %)而不会出现错误。

但无论如何,它现在的工作方式(确定文件存在,然后将绝对路径或 False 保存为模板变量似乎是一个更强大的解决方案,并且在模板中更具可读性。

再次感谢 supervacuo,您的建议和 cmets 提供了非常丰富的信息 - 我觉得因为他们我对 django 有了很好的了解!

【问题讨论】:

我应该提一下 - 如果文件不存在,我也尝试不将 LOCAL_CSS 设置为任何内容(这样% if LOCAL_CSS % 只会在变量 LOCAL_CSS 存在的情况下找到它),但这也没有工作。 您如何将LOCAL_CSS 加入您的模板中;上下文处理器?不管怎样,请也发布该代码。 呃,我没有答案,所以这实际上可能是问题所在。我认为模板默认可以访问设置。我猜不是这样? 【参考方案1】:

好的,这个兔子洞越来越深了(希望我们可以编辑现有的问题并回答一些一般有用的东西——一旦这一切都整理好了)。

os.path.exists() 的相对路径(如"local.css")是相对于您运行runserver 时所在的目录进行解释的。因此,尽管 os.path.exists('local.css') == True 在该目录中,但您的调试内容需要指定相对于 manage.py 的路径(或者为了简单起见将它们设为绝对路径)。

我不确定try .. finally 在这里的目的是什么,但也许只是这样做:

from django.conf import settings
import os

def local_static(context):
    # Make sure to return a dictionary
    return 
        'LOCAL_CSS': '/path/to/local.css' if os.path.exists('/path/to/local.css') else False,
        'LOCAL_JS': '/path/to/local.js' if os.path.exists('/path/to/local.js') else False,
        

一旦你确认它按预期工作,从那里开始构建(在local_settings.py 中进行if os.path.exists() 测试

【讨论】:

好的,我知道那里发生了什么 - 感谢您的帮助,您让我重回正轨。此外,在使用您在此处给我的代码之后,我能够将所有逻辑都放入 context.py 中(这很棒,因为我的一个附带目标是不需要安装站点必须手动将某些内容添加到 settings_local。 py 在他们更新后避免破坏他们安装的应用程序) 另外,我将在上面编辑我的兔子洞时通过 - 你是对的,太混乱了【参考方案2】:

(根据您的评论回复)

您实际上并没有将新的LOCAL_CSS 变量传递给模板,这绝对是您在继续之前需要解决的问题。 一些来自settings.py 的值默认可用(例如 MEDIA_URL),但这些值是由Django's default context processors 添加的,在TEMPLATE_CONTEXT_PROCESSORS 中定义。 MEDIA_URL 可用,例如,因为 django.core.context_processors.media

那么,向每个页面添加上下文变量的最佳方法是custom context processor。大致如下:

# app/context.py
from django.conf import settings

def local_static(context):
    # Make sure to return a dictionary
    return 
        'LOCAL_CSS': settings.LOCAL_CSS,
        'LOCAL_JS': settings.LOCAL_JS,
    

# settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
    # ... keep the defaults
    'app.context.local_static'
)
LOCAL_CSS = 'foo'

# template.html
 LOCAL_CSS 
# should output "foo" #

为此,您应该使用RequestContext 而不是普通的Context 来呈现您的模板; Django 文档说:

如果您使用 Django 的 render_to_response() 快捷方式来使用字典的内容填充模板,则默认情况下您的模板将被传递一个 Context 实例(而不是 RequestContext)。要在模板渲染中使用RequestContext,请将可选的第三个参数传递给render_to_response()RequestContext 实例

事实上,最简单的方法是通过using render() instead of render_to_response()

【讨论】:

感谢您的回复-我添加了信息以更新问题,但不幸的是问题仍然存在(当变量为 False 时该语句仍会执行),但感谢您,我已经回答了您上面的问题;-)

以上是关于如果评估的变量为 False,为啥我的 django 模板中的这个 IF 语句会执行?的主要内容,如果未能解决你的问题,请参考以下文章

为啥将变量与 0.0 进行比较会返回 false? [复制]

为啥 == false 评估为 false 而 [] == false 评估为 true?

为啥`false && true ||真`评估为真?

为啥 parseInt(key) === NaN 总是评估为 false

为啥 list.append 在布尔上下文中评估为 false? [复制]

为啥角度表达式评估为属性中的空字符串