Django:如何从模板中识别调用视图?
Posted
技术标签:
【中文标题】Django:如何从模板中识别调用视图?【英文标题】:Django: How can I identify the calling view from a template? 【发布时间】:2010-10-22 00:01:39 【问题描述】:短版:
是否有一种简单的内置方法来识别 Django 模板中的调用视图,而无需传递额外的上下文变量?
长(原始)版本:
我的一个 Django 应用程序有几个不同的视图,每个视图都有自己命名的 URL 模式,它们都呈现相同的模板。有非常少量的模板代码需要根据被调用的视图进行更改,太小以至于不值得为每个视图设置单独的模板的开销,所以理想情况下我需要找到一种方法来识别模板中的调用视图.
我尝试设置视图以传递额外的上下文变量(例如“view_name”)来识别调用视图,并且我还尝试使用% ifequal request.path "/some/path/" %
比较,但这些解决方案似乎都不是特别优雅。有没有更好的方法来从模板中识别调用视图?有没有办法访问视图的名称或 URL 模式的名称?
更新1:关于这只是我对MVC的误解的评论,我理解MVC,但是Django's not really an MVC framework。我相信我的应用程序的设置方式与 Django 对 MVC 的看法是一致的:视图描述 哪些 数据呈现,模板描述 如何 呈现数据。碰巧我有许多准备不同数据的视图,但它们都使用相同的模板,因为所有视图的数据都以相同的方式呈现。我只是在寻找一种简单的方法来从模板中识别调用视图(如果存在)。
更新 2: 感谢您的所有回答。我认为这个问题被过度思考了——正如我原来的问题中提到的那样,我已经考虑并尝试了所有建议的解决方案——所以我现在将它提炼成一个“简短版本”,现在位于问题的顶部.现在看来,如果有人只是简单地发布“不”,那将是最正确的答案:)
更新 3: Carl Meyer 发布了“否”:) 再次感谢大家。
【问题讨论】:
我不确定我是否能想到不同视图应该调用同一个模板的原因?你能详细说明吗?我认为这可能是您误解了 MVC 概念的情况 感谢您的评论。每个视图执行不同的 ORM 查询,但所有输出都采用相同的格式,因此为了 DRY 使用了通用模板。我已经用更多细节编辑了这个问题。 我会向模板传递一个额外的上下文变量。简单,不费吹灰之力的解决方案。为什么不呢? ***.com/questions/2491605/… 【参考方案1】:从 Django 1.5 开始,url_name
可以通过以下方式访问:
request.resolver_match.url_name
在此之前,您可以为此使用中间件:
from django.core.urlresolvers import resolve
class ViewNameMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
url_name = resolve(request.path).url_name
request.url_name = url_name
然后在 MIDDLEWARE_CLASSES 中添加这个,在模板中我有这个:
% if request.url_name == "url_name" % ... % endif %
考虑到 RequestContext(request) 总是传递给渲染函数。我更喜欢使用 url_name 作为 url,但可以使用 resolve().app_name 和 resolve().func.name,但这不适用于装饰器 - 而是返回装饰器函数名称。
【讨论】:
其实这个中间件是不需要的,因为请求已经提供了解析的url_name => request.resolver_match.url_name 感谢您的来信。实际上,request.resolver_match
是 2013 年在 Django 1.5 中引入的,而帖子是 2012 年的。*** 中应该有一个“已过时”的标志 :)
要在模板中使用request.resolver_match.url_name
django.core.context_processors.request
必须添加到设置TEMPLATE_CONTEXT_PROCESSORS
。
如果生成的模板来自从原始视图重定向的另一个视图,是否有办法找到原始 url。就像 xxx.com/create 将重定向到 xxxx.com/display 一样。重定向发生在 /create url 的 view() 中。我如何在 display.html 中知道它是否是从 /create 重定向的,以便我可以显示特殊消息?
我在将<body class="% request.resolver_match.url_name %">
添加到模板时收到Invalid block tag: 'request.resolver_match'
,我错过了什么?我在 TEMPLATE_CONTEXT_PROCESSORS 中有django.core.context_processors.request
【参考方案2】:
不,这将是一个坏主意。从模板中直接引用视图函数名称会导致视图层和模板层之间的耦合过于紧密。
这里更好的解决方案是 Django 的模板继承系统。定义一个公共父模板,在每个视图的版本中需要更改的(小)区域块。然后定义每个视图的模板以从父级扩展并适当地定义该块。
【讨论】:
谢谢,卡尔。正如我最初的问题中提到的,我想避免创建更多模板,因为模板差异非常小,但这种方法最有意义。 实际上,我正在考虑根据视图名称将 css 类添加到内容元素,但关于耦合,您可能是对的。【参考方案3】:如果您的 urls.py 和 views.py 中的命名是一致的,应该是这样,那么这将返回视图名称:
request.resolver_match.url_name
当你在模板中调用它时,一定要给它应用一些上下文。例如,我在这里使用它从我的详细视图中删除删除按钮,但在我的更新视图中,删除按钮仍然会出现!
% if request.resolver_match.url_name != 'employee_detail' %
【讨论】:
【参考方案4】:从 Django 1.5 开始,您可以通过 request.resolver_match 访问 ResolverMatch 的实例。
ResolverMatch 为您提供已解析的 url 名称、命名空间等。
【讨论】:
谢谢,我正在寻找已识别的view_name
!【参考方案5】:
一个简单的解决方案是:
def view1(req):
viewname = "view1"
and pass this viewname to the template context
def view2(req):
viewname = "view2"
and pass this viewname to the template context
在模板中访问视图名称为
viewname
你也可以在比较中使用它。
【讨论】:
感谢您的回答,但正如原始问题中所述,我已经尝试过,并且正在寻找更好的方法(如果存在)。【参考方案6】:我正在为一个帮助页面系统工作,我希望每个视图都对应于我的 cms 中的一个帮助页面,如果没有为该视图定义帮助页面,则会显示一个默认页面。我偶然发现了this blog,他们使用模板上下文处理器和一些 python 检查魔法来推断视图名称并用它填充上下文。
【讨论】:
【参考方案7】:这听起来像是您可以设置的通用视图的完美示例。
查看以下资源:
Django Book - Chapter 11: Generic Views Django Docs -Tutorial: Chapter 4 Django Docs - Generic Views这些链接应该可以帮助您相应地简化视图和模板。
【讨论】:
谢谢,但我的观点实际上已经在扩展通用观点。还是您建议我编写自己的通用视图? 例如djangobook.com/en/2.0/chapter11/#cn41, 'extra_context' 被传递给模板。这应该是解决您问题的简单方法。定义一个函数,或使用内置方法在“额外上下文”中传递数据,以便在模板中进行比较。 谢谢,但正如我原来的问题中提到的那样,我已经尝试过了,是的,我知道它有效。似乎应该有更好的方法来做到这一点。我想我的问题归结为:是否有一种内置方法可以从模板访问调用视图。【参考方案8】:如果您使用基于类的视图,您很可能有一个可以访问的 view
变量。
您可以使用其中的几种方法来确定调用了哪个视图或正在渲染哪个模板。
例如
% if view.template_name == 'foo.html' %
# do something
% else %
# other thing
% endif %
另一种选择是取出模板中您需要更改的部分并将其制成 sn-p,然后在模板中使用% include 'my_snippet.html' with button_type = 'bold' %
,将任意值发送到 sn-p 以便它可以确定显示什么/如何设置自己的样式。
【讨论】:
【参考方案9】:大多数通用视图(如果不是全部的话)都继承了 ContextMixin
,它添加了一个指向 View 实例的 view
上下文变量。
【讨论】:
【参考方案10】:为什么不尝试设置会话 cookie,然后从模板中读取 cookie。
根据您的观点设置 cookie
def view1(request):
...
#set cookie
request.session["param"]="view1"
def view2(request):
request.session["param"]="view2"
then in your ONE template check something like..
% ifequal request.session.param "view1" %
... do stuff related to view1
% endifequal %
% ifequal request.session.param "view2" %
... do stuff related to "view2"
% endifequal %
加特
【讨论】:
谢谢,但我希望降低复杂性,而不是增加复杂性 :)以上是关于Django:如何从模板中识别调用视图?的主要内容,如果未能解决你的问题,请参考以下文章