django书籍提供了本地技巧,以避免输入一长串参数作为上下文字典http://www.djangobook.com/en/2.0/chapter04/
它向懒惰的程序员推荐这一点,但指出了一些可能对性能产生影响的开销。
我想知道你们中的一些人是否在实际应用程序中使用本地技巧。你推荐它还是不好的做法?
答案 0 :(得分:76)
我不喜欢重复 - 我认为“干”,“不要重复自己”,是一个关键的编程原则。因此,我确实在类似的情况下使用了locals()
。 Django模板渲染远非这种情况的唯一情况:一般情况是“接受dict的函数或运算符,但不介意dict是否包含额外的条目”。 (例如,Python中的普通字符串格式是另一种这样的情况)。
然而,有一个反补贴原则:程序应该以可行的方式本地化理解 - 这有助于维护和重构(因为它不需要研究其他文件来检查哪些重构是可接受的)。这表明,对于locals()
情况,如果模板(或字符串格式等)是本地文字(在极少数情况下可能只使用很少的变量,因此locals()
不是一个巨大的胜利! - ),但在模板生活在不同文件中的正常情况下会出现问题。
因此,在大多数情况下,使用locals()
严重阻碍了重构。在Python的几乎所有情况下,局部变量及其名称都可以作为局部重构的一部分自由更改,因为它们没有“外部可见”的效果......但使用locals()
打破了 - 突然间你可以'安全地将变量重命名为不同的名称,提供更好的清晰度,重构代码流以消除对变量等的需要等,而不是每次都学习单独的模板文件来检查旧名称是否可能不是需要(并且可能编辑模板文件,这可能是非常重要的,例如,如果它以i18n / L10n的目的用几种不同的自然语言维护)。
因此,除了性能的次要问题之外,在“严重”,“生产”代码中使用locals()
的强烈压力 - 需要很长时间的代码术语维护,因此易于重构和局部性。所以,当我“编程最好,我知道如何”,而不是“偷工减料”时,我知道我最好避免locals()
。
毕竟,您希望在呈现模板的上下文中拥有的值不一定“自然地”可用作本地裸名称;可能它们中的一些或许多是计算结果,列表或词典中的项目等。在这种情况下,如果您只是将这些值累积到合适的字典中而不是将它们分配给本地的裸名称,则更容易避免使用locals()
“偷工减料”的诱惑。
这不是最简单的权衡,因为两个好的原则(避免重复和具有良好的地方性)不可避免地会发生冲突 - 因此,这是一个好问题!并没有一个完全容易受到黑色或白色的尖锐回答,这就是为什么我试图扩展双方的原因。最后,我认为这是“风格”方面之一,建议编程团队采用团队统一风格的指导方针并坚持下去 - 至少它不需要一遍又一遍地做出决定。问题出现的时间,并产生一个更加同质(从而可维护)的代码库。 [[我必须承认,这个特定的观点从未在我参加的团队的风格指导中得到明确解决,尽管其他许多人都有! - )]]
答案 1 :(得分:27)
我经常考虑做以下事情,但我不确定它是否真的有用。
class MyStruct(object):
pass
def my_view(request, id):
c = MyStruct()
c.customer = ..
c.invoice = ..
c.date = ..
return render_to_response('xxx,html',c.__dict__)
答案 2 :(得分:12)
我个人并不喜欢它。除了旧的Python格言“明确比隐含更好”之外,我可能没有理由倾向于我。我想知道我的模板到底发生了什么。
答案 3 :(得分:3)
我使用它没有任何问题(到目前为止!)。
我不是特别喜欢打字,这就是我喜欢它的原因。代码如
'customer' : customer,
'invoice' : invoice,
'date' : date
对我来说只是看起来很荒谬,如果我可以避免它,我会的。我喜欢Python的原因之一是它没有样板(虽然这不是真正的样板,但是它类似)。
答案 4 :(得分:2)
我想这取决于你在函数中定义了多少局部变量。
如果它与您想要返回模板的数字完全匹配,或者“额外”变量是简单结构,如整数或布尔值,那么我认为明确返回它们没有意义,因为这需要更多的工作。
但另一方面,如果你的视图有很多复杂的'辅助'变量,比如你在视图中使用的模型实例来生成你想要发送到模板的数据,那么你可能要考虑使用显式变量返回模板。
答案 5 :(得分:1)
我知道这是一个旧线程...目前不推荐使用render_to_response。使用render而不使用locals()。绕过所有当地人是一种不好的做法。 这是一个views.py示例:
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
@login_required
def mybooks(request):
entries = Book.objects.all()
return render(request, 'mybooks.html', {'entries': entries})
答案 6 :(得分:1)
为了减少views.py
中的混乱,同时保持明确:controllers.py
:
import sys
def auto_context(the_locals=None):
# Take any variable in the locals() whose name ends with an underscore, and
# put it in a dictionary with the underscore removed.
if the_locals is None:
# We can access the locals of the caller function even if they
# aren't passed in.
caller = sys._getframe(1)
the_locals = caller.f_locals
return dict([
(key[:-1], value)
for (key, value) in the_locals.items()
if key[-1] == "_"])
在views.py
:
from app.controllers import auto_context
def a_view(request):
hello_ = "World" # This will go into the context.
goodnight = "Moon" # This won't.
return render(request, "template.html", auto_context())
在template.html
中,使用{{ hello }}
。
您不太可能会给变量一个名称以下划线结尾的意外结果。因此,您将确切地知道进入模板的内容。使用auto_context()
或等效auto_context(locals())
。享受!
答案 7 :(得分:0)
我同意Alex的观点。当你能做到这一点时,不要看到创建一个类实例(正如niels建议的那样):
def my_view(request, id):
customer = ..
invoice = ..
date = ..
return render_to_response('xxx,html', locals())
如果您需要性能原因,则点线查找速度较慢。
如果您需要维护原因,这可以减少代码行数,甚至更多可读,并减少一些不必要的结构。