2011-08-07 33 views
1

在Django中,在一个模板变量的点理论上表示一个查找,基于分辨率的以下顺序上:Django的:模板字典/对象交叉引用

  • 字典查找。示例:foo["bar"]
  • 属性查找。示例:foo.bar
  • 方法调用。示例:foo.bar()
  • 列表索引查找。示例:foo[bar]

rendering a context in django 1.2(docs.djangoproject.com)。

在现实:

视图

... 
class Veggie(object): 
    def __init__(self, name): 
     self.name = name 
veggies = {'a': Veggie('carrot'), 'b': Veggie('lettuce')} 

basket = ['a', 'c', 'b'] 

return render_to_response('tpls/veggies.txt', 
     {'veggies': veggies, 'basket': basket}, 
     mimetype="text/plain") 

模板

Veggie by basket order, showing name 

{% for veg in basket %} 
    {{ veg }} 
    {{ veggies.veg.name }} 
{% endfor %} 

输出

Veggie by basket order, showing name 

    a 

    c 

    b 

该输出中没有素食名。

我认为这不是Django所说的那样。我明白,我可以写一个标签来解决这个问题。这很丑陋。

这是一个没有对Django开发团队修复,按照Django ticket 12486,因为“我们的目的是,Django的模板,可以读取和非程序员编写的,因此复杂的逻辑应该是视图代码或自定义模板标签。” (Luke工厂)

对于在这种情况下编写可读的模板代码的一些实用建议,我很感激(我有很多不同种类的“蔬菜”来解引用)。如果我们有模板编写人员 - 他们知道如何进行字典查找,那么是否值得从Django中脱身?

+0

我知道你知道是怎么回事,但我不明白为什么你认为违背它在文档中说。相反,您引用的文档非常清晰,并且其中没有任何内容表示它会将变量用作字典键。 –

回答

0

Django正在阻止您在模板中添加快速入侵来解决您的问题,因为它会强制模板作者和视图作者之间分离。想象一下,您销售了10,000种不同的蔬菜,并将它们保存在数据库表中。您是否真的想要将所有10,000种蔬菜的字典传递到模板中以启用您所描述的内容?

如果你用真正的模型而不是类和字典构建这个例子,你可能已经有了你想要的东西:一个“篮子”将是一个对象,它有一个外部键对“素食”的引用,所以basket_item.veggie将参照在素食表中的一排(呃,没有双关语)。您可以简单地通过篮子,并且从模板中引用时,素食项目将按需填充。为了提高效率,您可能最终在获取购物篮商品时使用.select_related,以便在单个SQL查询中预填充素食物品。

+0

由于快速入侵,问题不表达。我有一个主迭代器生成节点,几个对象的字典被引用。这些数据结构在plpgsql函数中进行了高度优化,运行速度比Django的ORM快几个数量级。我想你是在说“不要那样使用Django的代码”;我不同意这种做法。 – rorycl

2

Django的模板引擎在您的for循环中将veg作为字符串对待,但您试图将其用作表达式的一部分。虽然Django的模板引擎有时会遇到障碍,但您所做的只是无法验证。你想要做的是获得veggies与包含在对象veg名称的属性,点符号不工作的方式无论是在Python或Django的模板。当你说veggies.veg,它是寻找一个名为veg对蔬菜的属性,而不是命名ab,或c。这不是Django模板引擎的缺陷;这就是Python(以及我所知道的每种语言)的工作原理。

相反,刚吸起来,写一个模板标签访问属性,按名称,任意物体,或者通过模板,不需要在模板中的那种逻辑的篮子。

+0

感谢您的评论,丹尼尔。显然你说的是它的工作原理,但是规范指出dot *表示查找* - 所以它不能与Python代码相提并论。我认为你的“吮吸”评论总结了这种情况。 – rorycl

+0

中性化模板逻辑的宗教信仰有时是令人讨厌的,但有时候9/10倍的方法可以通过将逻辑放在视图中来实现你想要的内容,而在不可行的情况下,你总是可以创建作业的标签或过滤器。 –

1

Django的方式做到这一点是准备数据结构的视图渲染(我认为这就是为什么是“意见”被称为在Django“视图”的原因之一),例如

basket = [veggies[veg_id] for veg_id in basket_id_list] 

然后

{% for veg in basket %} 
    {{ veg.name }} 
{% endfor %} 

所以传递要呈现的结构,而不是你得到的地方结构。 django认为模板编写者愚蠢的人无法理解字典查找(或者一些python代码)是不正确的,django认为变量字典查找(以及任意的python代码)对于模板逻辑来说太复杂,并且有理由为了那个原因。我个人没有发现你的模板代码片段非常可读,但这是个人喜好。

如果你不同意这个意识形态或者它限制你的任务,那么很容易使用模板过滤器(无论如何都无法区分dct [var]和dct ['var']) ,过滤器只是一个单一的内容,在django本身没有任何好处),或者,如果这种意识形态真的很恶心,可以切换到不同的模板引擎,比如jinja2。

+1

问题是,并不是所有的数据结构都是线性的或者包含在您建议的方式中,或者可能需要低效的迭代才能将它们转换为独立结构。您的评论帮助我更清楚地了解了这一点(至少对我自己来说) - 谢谢。 – rorycl